razi zadaci za programiranje i jedi govanaFull description
uvod u programiranje: algoritmi,program,c++...Full description
ppn
XmLFull description
xmlFull description
Web programiranje - PrezentacijaFull description
Osnove programiranja robotaFull description
Zadatak Iz CNC ProgramiranjaFull description
Programiranje u matlabu
Tutorial de integração Flash com XMLFull description
Web programiranje - PrezentacijaFull description
Full description
CNC PROGRAMIRANJEFull description
Web programiranje - Prezentacija
JAVAFull description
Knjiga namenjena pocetnicima za savladavanje programiranja u programskom jeziku Java.
Linearno ProgramiranJeFull description
XML / PHP Programming
Uvod u XML Jedinica: 1 od 11
Šta je XML (Extended Markup Language)? Jedan od čestih pojmova upotrebljavanih u kontekstu današnjeg programiranja jeste XML. Ovaj pojam često se „bespravno” upotrebljava da prezentuje programski jezik, iako XML to, u stvari, nije. XML je, naime, samo način za serijalizaciju podataka, odnosno način na koji ćemo jednostavno i brzo moći da zapamtimo podatke (a da pri tom to nije baza podataka) i prosledimo ih nekome ko će ih takođe razumeti, jer poštujemo iste konvencije. Istorija XML-a počinje još 60-ih godina prošlog veka, kada je u Aj-Bi-Emu (IBM) konstruisan prvi višenamenski jezik za serializaciju podataka. Ovaj jezik zvao se GML (Generalized Markup Language). Uspeh ovog jezika, doveo je do nastavka istraživanja na ovom polju, koji je rezultirao jezikom SGML (Standard Generalize Markup Language). Deo SGML jezika iskorišten je za HTML-a (izgradnju HyperText Markup Language), dok je ostatak korišten za kompleksnije Internet aplikacije. 1996. godine počet je rad na uprošćenoj verziji SGML-a, čija je komplikovanost učinila da bude upotrebljavan samo u jakim velikim institucijama. Ovaj rad rezultirao je stvaranjem XML-a, za čiju se godinu nastanka smatra 1998. godina. Do danas, poznajemo dve verzije i nekoliko međuverzija XML-a: XML 1.0 i XML 1.1. Osnovna razlika je u rukovanju novim Unicode setovima, s obzirom na to da razvoj XML-a ne prati paralelno i proširenje Unicode-a. XML je već odavno standardni serijalizacioni jezik i na njemu su čak bazirani i neki drugi, specifični jezici serijalizacije: XHTML, WSDL, WML (WAP XML), RSS, RDF, OWL, SMIL, XSLT...
Sintaksa Sa sintaksom XML-a sreli smo se pisanjem bilo kog HTML taga, jer XML poštuje konvencije tagova, kao i HTML. Štaviše, i sama struktura tih tagova identična je HTML-u, jer se poštuje isti princip elemenata i atributa. Ipak, postoje neke osobenosti karakteristične isključivo za XML. Pre svega, XML je osetljiv na mala i velika slova (Case Sensitive). Zatim, ne sme u svom telu sadržati specijalne karaktere (njih treba prevesti u odgovarajuće ascii kodove). I konačno, trebalo bi da poseduje određenu strukturu (da ima koren, deklaraciju verzije...). XML se sastoji od tagova, odnosno, od elemenata i atributa. Tag je selekcija u nekom dokumentu markirana određenim oznakama i nazivom. Ove oznake su < i >, a naziv taga može biti bilo koji tekst, sve dok ostaju ispoštovane konvencije aktuelnog tag jezika. Na primer:
1
Ovo je pravilno napisan tag, ali nedovoljan da zaokruži jednu celinu u XML dokumentu. Da bi neka celina bila
zaokružena u XML-u, potrebna su bar dva taga. Jedan otvarajući i jedan zatvarajući, ili, eventualno, jedan „samozatvarajući” tag:
1
ili
1
Zatvarajući tag izgleda isto kao i otvarajući, osim oznake / koja se nalazi odmah na njegovom početku. Kada je tag samozatvarajući, oznaka / nalazi se pre njegovog završetka. Pravilno postavljena dva istoimena taga, čine jedan element i sve unutar njih čini sadržaj tog elementa:
1
Moj element
Logično, samozatvarajući tag ne može imati sadržaj, ali to ne znači da on nije element. Iako nije u stanju da „nosi” sadržaj, još uvek može imati atribute. Atributi su još jedan odeljak u kome XML element može nositi podatke. Nalaze se u otvarajućem tagu i označavaju se po sistemu ključ=vrednost:
1
Sadrzaj
ili
1
Jedan element može imati podelemente, koji mogu takođe biti elementi... To znači da jedan XML dokument ima strukturu stabla.
Struktura XML-a Svaki XML fajl trebalo bi da poseduje deklaraciju:
1
U deklaraciji prosleđujemo procesoru XML-a osnovne podatke o dokumentu: koja verzija XML-a je u pitanju, koji kodni raspored je korišćen u dokumentu... Zatim, opciona je i deklaracija tipa dokumenta koja označava set pravila koja će biti poštovana tokom parsiranja dokumenta. Ova deklaracija može biti napravljena direktno u dokumentu ili učitana iz eksternog izvora:
1
Nakon DTD-a sledi koreni (document) element dokumenta i konačno, naši serijalizovani podaci. Konačno, cela XML struktura izgleda ovako: Prolog (Ovo je opis dokumenta, nije obavezan) XML deklaracija (XML će funkcionisati i bez deklaracije, ali je poželjno da ona postoji) DTD Deklaracija (Za kompleksnije serijalizacije) Koreni element (Dokument) Elementi (Lista elemenata) Element – Atributi i vrednosti (Stavke iz liste) Podaci (Podaci po stavci) Recimo da želimo da stvorimo jedan XML dokument u kome će biti lista država:
Jasno je razaznati elemente pomenute u prethodnom delu lekcije. Root je koren dokumenta, drzava predstavlja jedan element; oznakaDrzave je atribut tog elementa, a naziv, glavniGrad i opis su ugnježdeni elementi (podelementi) elementa drzava.
Svaki XML dokument koji poseduje adekvatnu strukturu i poštuje sva sintaksna pravila, naziva se dobro formirani XML ili well formed XML. Ukoliko dokument sadrži i validacionu deklaraciju (koja ne izaziva validacionu grešku), naziva se validni, odnosno valid XML. Deklaraciju možemo i sami napisati, koristeći DTD (Document Type Definition) jezik. Na primer:
1 2 3 4 5
Ako bismo ovakvu definiciju snimili u fajl test.dtd, validacija u sledećem kodu (neki XML fajl), bila bi izvršena:
1 2 3 4 5 6 7
SrbijaBeogradOpis Srbije.....
Takođe, umesto referenciranja na eksterni fajl, definiciju dokumenta možemo implementirati i u sam XML fajl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
]> SrbijaBeogradOpis Srbije.....
Analizu kompletnog DTD jezika nećemo vršiti u ovom kursu. Alternativa DTD-u je XSD (Xml Schema Definition). XML šema je i sama predstavljena XML strukturom. XML šema:
1 2 3 4
5 6 7 8 9 10 11 12 13
XML dokument:
1 2 3 4 5 6 7 8 9
SrbijaBeogradOpis Srbije.....
Analizu kompletnog XSD jezika takođe nećemo vršiti u ovom kursu.
Pravila pisanja Postoje neki karakteri koje ne možemo uneti u XML sadržaj. Na primer, karater <. XML nije u stanju da interpretira ovaj karater adekvatno, zbog čega dolazi do greške. Da bismo predupredili ovakve greške, a ipak zadržali mogućnost da ovaj karakter sačuvamo u XML-u, koristimo enkodirane karaktere (reference na karaktere).
1
Vece - >
Ovako napisan element neće prijaviti grešku prilikom parsiranja. Komentarisani kod znači da parser neće uzeti u obzir taj deo koda. U XML-u komentar se piše na sledeći način:
1
odnosno
1
Sadržaj
Ovo pravilo važi samo za parsiranje XML-a. I komentar dodat na ovaj način i dalje će biti sastavni deo jednog XML dokumenta.
Pregled XML dokumenata Sadržaj XML dokumentata pregledamo na više načina:
Iz pretraživača - obično svaki pretraživač poseduje svoj mehanizam za pregled XML dokumenata, ali generalno, većina izgleda isto.
Prerađene, deserijalizovane od strane programa koji ih parsira - svakodnevno rukujemo mnoštvom XML dokumenata, a da to i ne znamo. Većina programa čuva podešavanja i ostale podatke u XML formatu.
U izvornom obliku - kao čist tekst.
XML dokument se može i stilizovati na klijentu, CSS i XSLT stilovima. Najvažnije iz ove lekcije: 1.
XML je jezik za serijalizaciju podataka, ali ne i jezik za njihovu obradu.
2.
XML fajlovi su tekstualni fajlovi, sa posebnom strukturom.
3.
XML se sastoji od tagova.
4.
XML je Case Sensitive – osetljiv na velika i mala slova.
5.
U XML strukturi razlikujemo elemente i atribute.
6.
Dobro formirani XML podrazumeva deklaraciju sa verzijom i kodnim rasporedom.
7.
XML mora imati koreni element.
PHP enkripcija (md5, sha, base64, rsa) Jedinica: 2 od 11 Jedan od bitnih koncepata u veb programiranju je i kriptografija. Kriptografija je bezbednosna komponenta koja omogućava šifrovanje i dešifrovanje sadržaja, kao i analizu samog šifriranja. Sa aspekta veb programera, ovaj pojam povezan je za mnoge praktične elemente i u zavisnosti od klase projekta, obično se kriptografski mehanizmi upotrebljavaju između više i mnogo više puta. Tačnije - uvek. Šifrovanje i dešifrovanje su jednostavne procedure, bazirane na veoma komplikovanim algoritmima, pa u tom domenu varira i nivo angažovanja programera. Ipak, u najvećem broju slučajeva, koristićemo već gotova rešenja i čak i za kompleksnije bezbednosne kontekste biće dovoljno osnovno poznavanje jezika. Obično se proces enkripcije i dekripcije (šifrovanje i dešifrovanje) izvršava prema nekom, već poznatom tipu. Osnovna dva tipa su simetrični (privatni) i asimetrični (javni) ključ. Simetrični ključ je određeni algoritam, koji biva primenjen na obe strane na identičan način (naravno, reverzno). Proces počinje tako što se običan sadržaj enkodira u šifrovani sadržaj uz pomoć određenog algoritma. Taj sadržaj se transportuje do druge strane i na drugoj strani se primenjuje isti algoritam za dešifrovanje. U međuvremenu, sadržaj je nevidljiv za bilo koga ko ne poseduje algoritam za dešifrovanje, odnosno, privatni ključ.
Mehanizam asimetričnog ključa podrazumeva dva ključa. Jedan za enkripciju, a drugi za dekripciju. Jedan od dva ključa je javan i koristi se za enkripciju. Taj ključ je dostupan svima koji hoće da izvrše i proslede kriptovani sadržaj vlasniku ključeva. Drugi ključ je privatni, i poseduje ga samo vlasnik. Pored podele na javne i privatne ključeve, postoji još jedna kriptografska podela: na jednosmernu i dvosmernuenkripciju. Ovo je znatno jednostavnija podela. Jednosmerna enkripcija podrazumeva da ono što šifriramo, više nikada ne možemo dešifrovati, dok dvosmerna enkripcija podrazumeva i dešifrovanje. Prema ovoj podeli, nameće se zaključak da su pomenute tehnike javnog i privatnog ključa obe deo dvosmerne enkripcije. To je tačno. U tom slučaju, postavlja se pitanje: Šta je i čemu služi jednosmerno šifrovanje? Zašto bismo šifrovali sadržaj koji nikada nećemo moći da dešifrujemo? Odgovor je da je ovo, zapravo, veoma često korišćena tehnika. Štaviše, kada je u pitanju pravljenje standardnih veb aplikacija, mnogo je korišćenija od dvosmerne enkripcije.
Jednosmerna enkripcija Pitali smo se, u prethodnom pasusu, čemu služi jednosmerna enkripcija? Kada se registrujemo na neki sajt (na primer Facebook) i unesemo šifru, tu šifru niko ne može da vidi, čak ni mi sami, jer ona, zapravo i nije uskladištena u bazi u svojoj izvornoj formi. Umesto toga, šifra se prvo kriptuje (jednosmernom enkripcijom) i tek onda smešta u bazu. Kada se logujemo na sajt, unosimo našu pravu šifru, sistem je kriptuje i poredi sa kriptovanom vrednošću u bazi. Ako se vrednosti poklapaju, znači da je šifra u redu. Kada kažemo sistemu da smo izgubili šifru, on nam nikada neće poslati našu šifru, jer je ni sam ne zna, već sistemski generisanu, novu šifru. Pogledajmo još jedan čest vid upotrebe jednosmernog šifrovanja. Zamislimo jedan veb pretraživač (Google npr.), koji svakog dana pretraži milione sajtova. On u svojoj bazi skladišti sve strane svih sajtova. Kada u svakodnevnoj pretrazi naiđe na sajt na kome je već bio i koji ima u bazi, besmisleno je da ga ponovo smešta u bazu ukoliko je sajt nepromenjen. Ali, da bi proverio da li postoje izmene, potrebno je da pregleda celu stranu na Internetu i uporedi je sa stranom u bazi. Ovo može biti veliki posao kada su milioni sajtova u pitanju i umesto toga, pretraživač za svaku stranu pamti i njenu kriptovanu reprezentaciju. Na kraju, umesto da poredi kompletnu stranu, poredi samo tu reprezentaciju. S bzirom na to da jednosmerna enkripcija, ma koliko veliki bio sadržaj (mada ovo zavisi od algoritma), rezultira vrednošću jedne određene dužine, dobija se ogromna ušteda u brzini i prostoru. PHP kroz ugrađene ili dodatne funkcionalnosti podrazumeva sve moderne kriptografske mehanizme. Što se tiče jednosmerne enkripcije, u PHP-u postoji nekoliko funkcija za kreiranje kriptovanih kodova na ovaj način. To su crypt(), md5(), sha()...
crypt() Ovo je osnovna funkcija za jednosmerno kriptovanje u PHP-u. Ona prihvata minimalno jedan parametar. Tekst koji treba kriptovati. Alternativno, moguće je dodavanje i drugog parametra, salt. To je zapravo set karaktera na osnovu koga će biti izvršena enkripcija. Salt vrednost može biti 2 – 12 karaktera, u zavisnosti od sistema, odnosno, algoritma koji je crypt funkcija u stanju da koristi. Od salt vrednosti će zavisiti i to koji će algoritam biti korišćen. Ukoliko se eksplicitno ne naglasi, salt će biti dvo-karakterni i biće korišćen DES algoritam (Data Encryption Standard). Pored njega, možemo koristiti i extended DES, md5 i blowfish algoritme (ukoliko sistem dozvoljava). Da bismo naglasili da želimo da upotrebimo neki od ovih algoritama, moramo napisati specifičan salt string:
1
echo crypt('test','bilosta');
Ovo će aktivirati standard DES salt i samo će prva dva karaktera biti uzeta u obzir. Takođe, u enkripciji, biće iskorišćeno samo osam prvih karaktera stringa koji se kriptuje. Ako bi salt string bio duži od osam karaktera, bio bi aktiviran extended DES algoritam:
1
echo crypt('test','$1$bilosta');
Oznaka $1$ aktivira Md5 algoritam.
1
echo crypt('test','$2$bilosta');
Oznaka $2$ aktivira blowfish algoritam. Proveru aktuelnog crypt algoritma možemo proveriti konstantom CRYPT_SALT_LENGTH:
1
echo CRYPT_SALT_LENGTH;
Ova konstanta vraća kao rezultat dužinu enkripcije (2 za des ili 12 za md5). Algoritme koje sistem podržava možemo proveriti konstantama: CRYPT_STD_DES, CRYPT_EXT_DES, CRYPT_MD5, CRYPT_BLOWFISH. One sadrže vrednost nula ili jedan (true ili false) u zavisnosti od toga da li je enkripcija podržana ili nije.
md5() (Message Digest Algorithm) md5 je PHP funkcija koja vrši jednosmernu enkripciju stringa (bilo koje veličine), provlačeći ga kroz 128-bitni algoritam i kreirajući od njega heksadecimalnu vrednost dužine 32 karaktera. Ova funkcija najčešće se koristi za skladištenje i proveru šifara u bazama korisnika i sl. Može i ne mora primiti dodatni parametar, koji naznačava da li rezultat treba da bude string ili binarna reprezentacija. Iako ima dobar algoritam i enkripcija je jednosmerna; treba paziti prilikom rukovanja ovom funkcijom. Postoji veliki broj sajtova na Internetu, koji omogućavaju dekripciju md5 kodova u izvorni sadržaj (na primer http://www.md5decrypter.com). Ovo ne rade tako što stvarno dekriptuju, već tako što sadrže ogromne baze reči kriptovanih md5 enkripcijom, pa do „dekriptovanih” rezultata dolaze jednostavnim poređenjem. Zbog toga treba uvek od korisnika (ako želimo da njegova šifra bude kriptovana md5 enkripcijom) da tražimo da unese nestandardnu sekvencu karaktera kao šifru. Na primer: ako kriptujemo reč petar dobićemo sledeći kod: 597e3b12820151caa6062612caec8056. Ako ovaj kod probamo da dekriptujemo (putem pomenutog sajta), dobićemo njegov izvorni oblik - reč petar. Ali, ukoliko bismo kriptovali reč petar123, bilo koji md5 dekripter, teško da bi bio u stanju da dekriptuje ovaj sadržaj, jer je nestandardan. Sintaksa funkcija md5 je sledeća:
1
md5("petar");
ili:
1
echo md5("petar");
Ukoliko želimo binarni, row izlaz, treba dodati još jedan parametar, tipa boolean:
1
md5("petar", 1);
ili
1
md5("petar", true);
Postoji i srodna funkcija, koja radi isto što i md5, ali umesto stringa, prihvata fajl (bilo kog tipa):
1 2 3
md5_file("c:/proba.txt"); md5_file("c:/app.exe");
Za ovu funkciju, takođe važi opcioni drugi parametar, za binarni izlaz:
1
md5_file("c:/indeksiranjeLucene.exe",1);
ili
1
md5_file("c:/indeksiranjeLucene.exe",true);
sha1() (secure hash algorithm) Funkcija sha1 ima istu implementaciju kao i funkcija md5, sa razlikom u samom algoritmu (sha ima 160-bitni algoritam) i izlazu (sha1 ima izlaz od 40 karaktera, odnosno 20 karaktera, ako je u pitanju binarni raw izlaz). Sva sintaksna pravila su ista kao i za funkciju md5:
Sledi spisak svih algoritama koje pokriva funkcija hash().
md2,md4
md5
sha1
sha256
sha384
sha512
ripemd128
ripemd160
ripemd256
ripemd320
whirlpool
tiger128,3
tiger160,3
tiger192,3
tiger128,4
tiger160,4
tiger192,4
snefru
gost
adler32
crc32
crc32b
haval128,3
haval160,3
haval192,3
haval224,3
haval256,3
haval128,4
haval160,4
haval192,4
haval224,4
haval256,4
haval128,5
haval160,5
haval192,5
haval224,5
haval256,5
Ove algoritme dobili smo funkcijom hash_algos(). Ona kao rezultat vraća niz svih algoritama dostupnih sistemu i funkciji hash. Funkcija hash takođe ima i alternativni parametar row, za emitovanje rezultata u binarnoj formi, kao i već pominjanu varijaciju hash_file(), za provlačenje kompletnog fajla kroz algoritam.
base64encode() i base64decode() Base64encode pretvara tekst u njegovu MIME base64 reprezentaciju. Ovo zapravo nije prava enkripcija, već više mali trik koji može poslužiti u trenucima kada nije neophodna jača bezbednost:
RSA Da bismo ostvarili dvosmernu enkripciju uz pomoć javnog ključa, nisu nam dovoljne ugrađene PHP funkcije zbog čega ili moramo pisati sopstvene algoritme, ili koristiti gotove biblioteke. Jedan od češće korišćenih dvosmernih algoritama sa javnim ključem je RSA. Postoje razne implementacije RSA algoritma. Jedna postoji i u Pear paketu Crypt_RSA. Podsetićemo da je konzolna komanda za instalaciju Pear paketa : pear install Crypt_RSA Nakon uspešne instalacije Crypt_RSA, možete isprobati sledeći jednostavan primer implementacije RSA enrkipcije. Primer je detaljno komentarisan, ipak, preporučujemo upoznavanje sa ovom bibliotekom kroz oficijelnu dokumentaciju: http://pear.php.net/package/Crypt_RSA/docs/
//import Pear RSA paketa require_once 'Crypt/RSA.php'; //KREIRANJE KLJUCEVA //keriranje para kljuceva $kljucevi = new Crypt_RSA_KeyPair(128); //broj 128 je broj bita, odnosno jacina enkripcije //dodeljivanje kljuceva promeninljivima $javniKljuc = $kljucevi->getPublicKey(); $privatniKljuc = $kljucevi->getPrivateKey(); //ENKODIRANJE //preuzimanje tekstualnog sadrzaja, koji treba kriptovati $txt = "moj tekst"; //kreiranje Crypt_RSA objekta $rsaObj = new Crypt_RSA(); //Pozivanje metoda encrypt i kriptovanje sadrzaja javnim kljucem $kodirano = $rsaObj->encrypt($txt,$javniKljuc); //Rukovanje kodiranim sadrzajem. //Ovde bi sadrzaj mogao ici i u tekst fajl echo($kodirano); //DEKODIRANJE //kreiranje Crypt_RSA objekta $rsaObjDek = new Crypt_RSA(); //dodela kljuca objektu $rsaObjDek->setParams(array('dec_key' => $privatniKljuc)); //Preuzimanje kodiranog sadrzaja, iz fajla ili stringa i poziv metode decrypt $dec = $rsaObjDek->decrypt($kodirano); //Rukovanje dekriptovanim sadrzajem echo " " . $dec
Najvažnije iz lekcije: 1.
Dve osnovne vrste šifrovanja i dešifrovanja su sinhrono i asinhrono.
2.
Sinhrono – privatni ključ, manja bezbednost.
3.
Asinhrono – javni ključ, veća bezbednost.
4.
Enkripcija se deli na jednosmernu i dvosmernu.
5.
Jednosmerna enkripcija podrazumeva enkripciju, ali ne i dekripciju.
6.
Najkorišćeniji jednosmerni algoritmi u PHP-u su md5 i sha1.
7.
Md5 je 128-bitna enkripcija, dok je sha1 160-bitna enkripcija.
8.
Funkcije md5 i sha1 startuju se na identičan način (sa razlikom u nazivu) - md5("tekst",true);
9.
Funkcija hash, kao parametar prihvata algoritam, sadržaj i opciono tip izlaza (binary ili tekst).
SimpleXML klasa – Parsiranje XML-a, pristup elementima i atributima Jedinica: 3 od 11 Jedino što XML dokument čini onim što jeste, zapravo je njegova struktura. Jedan XML fajl je, u stvari, običan tekstualni fajl, koji sadrži XML strukturu. To znači da praktično i nije previše bitan način na koji ćemo taj fajl tretirati, sve dok smo u stanju da iz njega izvučemo relevantne podatke. Ako imamo jedan tag:
1
Pozdrav xml
potrebno je da na neki način sistematski izvučemo rečenicu „Pozdrav xml” iz njega. Upravo ovo, samo ne u tako minimalističkoj formi, rade mnogi sistemi za rad sa XML-om. Jedan od njih je i klasa SimpleXML. SimpleXML je jednostavna, ali moćna klasa koja ima mogućnost čitanja, kreiranja, modifikacije i snimanja XML dokumenata. Funkcioniše tako što kreira SimpleXML objekat iz nekog izvora (string ili fajl). Zatim je taj objekat dostupan tokom koda, pri čemu sam objekat predstavlja koreni element dokumenta, a njegovi atributi njegove podelemente. Na primer:
1 2 3 4 5 6 7 8
moj prvi element moj drugi element
Ako bismo ovaj XML dokument smestili u jedan SimpleXML objekat, njegova struktura bi izgledala ovako:
SimpleXML objekat bi predstavljao ceo dokument. Odnosno, njegov koreni element mojxml. Svaki nivo podelemenata bio bi, u okviru ovog objekta, predstavljen kao niz:
Evo kako bi ovaj primer izgledao u pravom kodu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//Pravljenje xml dokumenta i smestanje u promenljivu xmlTekst $xmlTekst = << moj element moj element 123 XML; //Kreiranje SimpleXMLElement objekta xml, na osnovu kreiranog xml dokumenta xmlTekst $xml = new SimpleXMLElement($xmlTekst); //Nakon kreiranog objekta, lako dolazimo do elemenata kroz strukturu samog objekta //koja se kreira na osnovu strukture xml dokumenta echo $xml->element[0];
U primeru smo iskoristili Herodoc string sintaksu. Tako da možete jednostavno kopirati kod u okruženje. Mnogo češće, XML dokument neće biti vidljiv unutar same funkcionalnosti, već će doći spolja, kroz string. Iz primera vidimo da smo inicijalizovali objekat naredbom new SimpleXMLElement(). SimpleXMLElement je centralni objekat klase. Kao konstruktor prosledili smo mu string sa XML dokumentom, što je i jedini obavezan parametar ovog konstruktora. Pored toga, ovaj konstruktor prihvata i nekoliko alternativnih parametara:
1
new SimpleXMLElement($xmlTekst, LIBXML_DTDVALID);
Prvi dodatni parametar konstruktora je option. Konstanta koja aktivira propratnu opciju prilikom konstrukcije objekta. Ovo su konstante iz libxml biblioteke za rukovanje XML-om. Listu svih parametara možete naći na sledećoj adresi: http://www.php.net/manual/en/libxml.constants.php
Ukoliko želimo više opcija, odvajamo ih oznakom |. Sledeći parametar je data_is_url. Umesto iz stringa, klasa će biti formirana iz dokumenta sa URL adrese. Naravno, u tom slučaju, i sam izvor mora biti zamenjen izvorom sa veba:
1
$xml = new SimpleXMLElement("http://mojxmldokument.xml",null,true);
Morali smo da postavimo i drugi parametar, ali samo zato da se PHP ne bi „zbunio” i „zabrojao” sa parametrima. Treći parametar (true) označava da će XML dokument biti preuzet sa URL-a. Poslednji i pretposlednji parametar (ns i is_prefix) tiču se prostora imena dokumenta. Ukoliko je is_prefix (poslednji parametar) true, odnosno, aktivan, biće uzet u obzir i prostor imena dokumenta. Ali, samo pod uslovom da je prostor imena naglašen u prethodnom parametru i adekvatno definisan u samom XML dokumentu:
1 2 3 4 5 6 7 8 9 10 11 12 13
$xmlTekst = << moj element moj element 123 XML; $xml = new SimpleXMLElement($xmlTekst,null,false,"mojNs", true); echo $xml->element[1];
Najčešće ćemo XML dokument dobavljati iz fajla. Na primer:
1 2
$xmlTekst = file_get_contents("xmlFajl.xml"); $xml = new SimpleXMLElement($xmlTekst);
Umesto toga, možemo direktno konstruisati objekat funkcijom simplexml_load_file():
1
$xml = simplexml_load_file("xmlFajl.xml");
U pozadini ove funkcije se ne događa ništa drugo do konstrukcija SimpleXMLElement objekta na već objašnjeni način. Varijacija funkcije simplexml_load_string() funkcioniše isto, samo što, umesto parametra prihvata string, a ne fajl:
1
$xml = simplexml_load_string($xmlTekst);
Kada jednom imamo objekat sa dokumentom, možemo ga čitati kao standardan niz:
1 2
for($i=0;$ielement);$i++) echo $xml->element[$i];
ili
1 2
foreach($xml as $element) echo $element;
Kada se jednom domognemo nekog elementa, njegove podelemente možemo pročitati kroz niz (kao u prethodnim primerima, ali možemo od njega stvoriti zaseban element i tako ga iščitavati. Jedan od načina da to uradimo je metodom children(). Ovaj metod, jednostavno, kao rezultat, vraća kompletan niz podelemenata aktuelnog elementa:
Pogledajmo kako to izgleda u praksi. Jedan od načina upotrebe XML-a je za kreiranje RSS-a, odnosno, RSS feed-ova. Na primer: http://rss.cnn.com/rss/cnn_world.rss Ako otvorite ovu adresu u pretraživaču, dobićete sledeću formu strane (sadržaj će biti različit, jer su u pitanju aktuelne vesti):
Pretraživači imaju ugrađen mehanizam za prepoznavanje RSS feed-ova i obično ih emituju na ovakav način. Ako bismo otvorili izvorni kod ovog feed-a, videli bismo zastrašujuću količinu teksta. Ali, zapravo je u pitanju vrlo jednostavna XML struktura, sa specifičnim osobenostima. Nešto poput sledećeg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Očigledno je da je koreni element dokumenta rss i da je njegov podelement channel, koji u stvari, sadrži vesti (elementi item). Kada ovo znamo, vrlo jednostavno možemo pročitati i kontrolisati feed, odnosno, napraviti RSS čitač:
1 2 3 4 5 6
$xml = new SimpleXMLElement("http://rss.cnn.com/rss/cnn_world.rss",null,true); foreach($xml->channel->item as $vest) { echo $vest->title . " "; echo $vest->description . ""; }
Naravno, ograničili smo podatke na izlazu na title i description, ali vi možete uneti i ostale podatke.
Modifikacija XML dokumenta Do sada smo uspeli da pročitamo XML dokument, ali ne i da intervenišemo na njegovom sadržaju, odnosno, strukturi. Ovo bismo, ako želimo da menjamo neki dokument, morali uraditi tako što ćemo sekvencijalno proveravati sve elemente, jedan po jedan i prepisivati ih u novi dokument sa eventualnim modifikacijama. Ukoliko kreiramo dokument od početka, ovaj proces se razlikuje u tome što neće postojati deo sa čitanjem, već samo upis u novi dokument.
Isprva, kreiramo SimpleXML objekat sa korenim elementom:
1
$xml = new SimpleXMLElement("");
Možemo odmah uneti i deklaraciju:
1
$xml = new SimpleXMLElement("");
Sada, možemo rukovati kroz ovaj dokument dodajući mu podelemente i atribute:
1 2 3 4 5 6 7 8 9 10 11
//DODAVANJE JEDNE KNJIGE //kreiranje elementa knjiga $knjiga = $xml->addChild("knjiga"); //dodavanje atributa elementu knjiga (id i isbn) $knjiga->addAttribute("id","01"); $knjiga->addAttribute("isbn","1234567"); //dodavanje podelemenata knjige $naslov=$knjiga->addChild("naslov","Petrova knjiga"); $naslov=$knjiga->addChild("autor","Petar Petrovic"); //emitovanje xml-a u string echo $xml->asXML();
Blok koda (izuzev poslednje linije koja emituje XML u string), možemo ponavljati onoliko puta koliko imamo podataka. Iz primera možemo izdvojiti nekoliko novih naredbi (metoda klase SimpleXMLElement): addChild() dodaje podelement elementu. Može imati samo jedan parametar (naziv podelementa), dva parametra (naziv podelementa i njegov sadržaj) ili tri parametra, pri čemu treći parametar predstavlja prostor imena). addAttribute() Dodaje atribut postojećem elementu. Prihvata isti broj i tipove parametara kao i metod addChild() (naziv, vrednost i prostor imena). asXML() Ovaj metod ima dve varijante izvršavanja. U jednoj (ako nema parametara) vraća string kao rezultat, dok u drugoj varijanti, snima XML u fajl čija je putanja uneta kao parametar (asXML("mojfajl.xml")), a kao rezultat vraća boolean tip (uspešno ili neuspešno). Umesto na ovaj način, možete XML dokument kreirati i ručno, pisanjem u string red po red:
SimpleXML je brza, jednostavna i efikasna biblioteka za rukovanje XML dokumentima.
2.
Osnovna klasa SimpleXML biblioteke je SimpleXMLElement.
3.
SimpleXMLElement sadrži jedan XML element ili dokument i sve njegove podelemente.
4.
SimpleXMLElement se inicijalizuje unosom XML dokumenta kao parametra.
5.
SimpleXMLElement može biti kreiran i funkcijom simplexml_load_file().
6.
Dodavanje elemenata SimpleXMLElement objektu se vrši metodom addChild().
7.
Dodavanje atributa SimpleXMLElement elementu, vrši se naredbom addAttribute.
8.
SimpleXMLElement objekat se emituje na izlaz u formatu XML dokumenta metodom asXML().
Xpath XML upiti Jedinica: 4 od 11 XPath je jezik za rukovanje podacima iz XML dokumenta. Za razliku od sekvencijalnog pregleda, ovaj jezik omogućava pronalaženje ciljnih čvorova uz pomoć upita. XPath nije ograničen na određenu programsku strukturu jezika i možemo ga koristiti uz pomoć bilo koje od biblioteka koje rukuju XML-om, pa čak i SimpleXML-om koji smo obradili u prethodnoj lekciji. Da bismo u SimpleXML-u aktivirali XPath upit, koristimo metod XPath:
1 2
$xml = new SimpleXMLElement($xmlTekst); $r = $xml->xpath('/izdanja/knjiga');
(primer dodeljuje promenljivoj $r sve elemente knjiga) Rezultat XPath upita je jedan ili niz elemenata i kada jednom do njega dođemo, možemo mu se obraćati na standardne načine.
Navigacija Ono što je, dakle, bitno u XPath-u, jesu upiti kojima ćemo doći do željenih elemenata. Pri tome, već smo videli jednu od sintaksnih oznaka: /. Ova oznaka ima isto značenje kao i u fajl sistemu. Određuje dubinu u putanji. Da bi nam bilo jasnije, vratićemo se na primer XML dokumenta iz prethodne lekcije:
U malopređašnjem primeru upotrebili smo upit: /izdanja/knjiga. Ovaj upit vraća sve knjige koje se nalaze u elementu izdanja (da postoji još neki podelement u elementu izdanja, ne bi bio izlistan). Ako bi postojao još neki podelement u elementu izdanja (na primer casopis), njega bismo mogli dobiti upitom /izdanja/casopis. Pri tom bi, naravno, sve knjige bile izignorisane. Umesto po nazivima elemenata, mogli smo podatke pronaći i po dubini. U prethodnom primeru, mi naglašavamo da hoćemo sve elemente knjiga roditelja izdanja. Kada bi element izdanja promenio ime, kompletan koncept bi se srušio, jer putanja ne bi bila tačna. Zato, umesto naziva elementa, možemo samo naznačiti njegovu dubinu:
1
//knjiga
Sada dobijamo uvek isti rezultat, ma kako se zvao roditeljski element elementa knjiga. Pored oznaka //, xpath koristi i oznake . i .. za navigaciju, pri čemu je . oznaka za aktuelni element, dok je .. oznaka za roditeljski element. Dobavljanje atributa vrši se oznakom @ kojoj sledi naziv ciljnog atributa:
1
$r = $xml->xpath('//knjiga/@id');
Ovaj primer vratiće sve atribute id svih knjiga dokumenta izdanja.
Džoker znaci XPath upiti poznaju i džoker znak *. Ovaj znak važi i za elemente i za atribute i zamenjuje bilo koji naziv. Sledeći upit će umesto atributa id, prikazati sve atribute (svih knjiga):
1
$r = $xml->xpath('//knjiga/@*');
Džoker je primenjiv i na elemente:
1
$r = $xml->xpath('//*/@*');
Upit će vratiti sve atribute elemenata koji odgovaraju dubini // (ovaj primer bi, naravno, funkcionisao i bez džokera ('///@*')). Kao džoker može se upotrebiti i oznaka (funkcija) node(). Ona, jednostavno, očekuje nod bilo kog tipa:
1
$r = $xml->xpath('//knjiga/node()')
Node() je jedna od funkcija iz node test seta. Osim nje, postoji još nekoliko naredbi iste grupe:
Comment() – izlistava samo XML komentare.
Processing-instructions() – rukuje direktivama dokumenta (npr, deklaracijom). Ukoliko se ostavi bez parametara, izlistava sve instrukcije. Ukoliko se prosledi parametar, izlistava samo željene instrukcije.
Text() – izlistava tekstualne nodove
Preuzimanje elemenata nelinearno Ponekad hoćemo da izlistavamo podatke sa dve različite putanje. Na primer, sve elemente jednog elementa, i sve atribute drugog. Ovo je moguće operatorom | :
1
$r = $xml->xpath('//autor/@id* | //naslov');
Dodatno uslovljavanje Uslovi po kojima smo do sada vršili pretragu nisu omogućavali precizno filtriranje dobijenih podataka u dokumentu. Svaki rezultat koji smo do sada dobili nije bio precizan do nivoa jednog podatka. Da bismo dobili još preciznije rezultate pretrage, koristimo predikate i funkcije. Predikati omogućavaju da se eksplicitno obratimo nekom od redova. Na primer, ako bismo želeli da rezultat sledećeg upita ograničimo na samo jedan red:
1
$r = $xml->xpath('/izdanja/knjiga');
morali bismo, u obradi rezultata, preduprediti brojanje više od jednog reda. Ovo nije praktičan način, ukoliko već radimo sa XPath-om. Mogli smo to uraditi jednostavnije putem predikata XPath upita:
1
$r = $xml->xpath('/izdanja/knjiga[0]');
Ovaj primer prikazuje prvi element u nizu elemenata knjiga dobijen uz pomoć predikata. Izrazi predikata uvek se nalaze u uglastim zagradama. Ovaj vid filtriranja je veoma moćan, jer parametar (u našem primeru 0) nije ograničen samo na broj kao u primeru, već je može biti i kompletan izraz, pa čak i funkcija, uključujući i aktuelne podatke. Na primer, mogli bismo reći da hoćemo drugu knjigu po redu: knjiga[0+1], što znači da je moguće uneti i aritmetičku operaciju (naravno, ne bismo nikada napravili ovakav upit već samo [1]). Možemo kreirati izraz i na osnovu aktuelnog podatka:
Vraća knjige čiji element autor ima vrednost Petar Petrovic. ili
1
$r = $xml->xpath('/izdanja/knjiga[@id=01]');
Vraća element knjiga čiji atribut id ima vrednost 01. Ovde koristimo znak = za poređenje. Pored njega moguće je i korišćenje i drugih standardnih operatora poređenja: < >… Predikate možemo koristiti i u kombinaciji sa funkcijama:
1
$r = $xml->xpath('/izdanja/knjiga[last()]');
Vraća poslednji element knjiga u dokumentu. Nakon uslova, možemo nastaviti sa izgradnjom putanje:
1
$r = $xml->xpath('/izdanja/knjiga[last()]/@id')
XML prostori imena i pisanje XML-a u fajlove Jedinica: 5 od 11 Da bismo izbegli preklapanje istoimenih, ali raznorodnih XML struktura jednog dokumenta, između ostalog, možemo koristiti i prostore imena. Prostori imena obezbeđuju kontekstualni integritet podataka koji se u njemu nalaze. Na primer:
1 2 3 4 5 6 7 8 9 10 11 12
visa virtuonvisa elektronmaster cardmsi proizvodjac> < proizvodjac >asusintel
Ovaj XML dokument sadrži podatke o karticama, ali njegovi elementi, u stvari, nose potpuno različite tipove podataka. Jedan element sadrži platne kartice, a drugi grafičke. Ipak, parser ne bi bio u stanju da vidi razliku između ovih tipova i svi podaci bi bili tretirani na jedan isti način. Zbog toga, ova dva tipa podataka možemo razdvojiti prostorima imena:
1 2 3 4 5 6 7 8 9 10 11 12
visa virtuonvisa elektronmaster cardmsiasusintel
Vidimo da je dodato nekoliko komponenti prethodnom XML dokumentu.
Svaki element (podelement) sadrži prefiks odvojen dvotačkom od naziva elementa. U prvom setu, to je platne, a u drugom graficke. Ovo nam omogućava da stavimo željene elemente u željene prostore imena.
xmlns:platne="platneKartice" – Ovo je deklaracija prostora imena: xmlns: (ključna reč koja označava početak deklarisanja prostora imena), platne (prefiks prostora imena (ovaj prefiks mora se poštovati u nazivima elemenata)), ="platneKartice". (Identifikator prostora imena. Nije bitno šta će ovde pisati, sve dok je unikatno na nivou dokumenta, jer ćemo se na osnovu ovog imena kasnije obraćati prostoru imena. Najčešće se, kao identifikator prostora imena, unosi veb lokacija na kojoj se nalazi opis tog prostora imena.)
Čitanje prostora imena može se ostvariti na različite načine. Koristeći SimpleXML, ovaj proces je vrlo jednostavan:
Pod pretpostavkom da promenljiva $xml sadrži XML dokument iz prethodnog primera, sve elemente jednog prostora imena možemo izvući metodom children(). Ova metoda vraća sve podelemente jednog elementa, ali može prihvatiti i opcioni parametar - namespace. U tom slučaju, za vraćanje svih podelemenata, moraće da bude ispunjen jedan uslov – poklapanje prostora imena navedenog kao parametar sa nekim od postojećih prostora imena. Osim unutar elemenata, prostore imena je moguće definisati i u samom korenu dokumenta. Tada, postavljamo sve definicije prostora imena jednu za drugom, kao zasebne atribute korenog elementa:
1 2 3 4 5 6 7 8 9 10 11 12
visa virtuonvisa elektronmaster cardmsiasusintel
Pisanje XML dokumenata u fajlove Možemo slobodno reći da smo čitanjem i parsiranjem XML dokumenta ili kreiranjem sopstvenog, uradili teži deo posla u njegovoj obradi. Drugi, obično jednostavniji deo, jeste njegovo emitovanje, odnosno, upis na neki sistem. Najčešće, to će biti lokalni fajl sistem. asXML() i save() asXML() metod SimpleXMLElement klase upotrebili smo već za emitovanje XML-a na stranu. Na isti način, XML možemo emitovati i u fajl:
1
$xml->asXML("mojFajl.xml");
Ovo je vrlo jednostavno, ali naravno, funkcioniše samo ukoliko rukujemo samo sa SimpleXML objektom. Ukoliko bismo rukovali sa DOMDocument objektom (ovu biblioteku ćemo obraditi u naredim lekcijama), upotrebili bismo metod save():
1
$dom->save("mojFajl.xml");
Ručno pisanje Ponekad ćemo XML dokument kreirati bez upotrebe specijalizovanih klasa. Jednostavno, sekvencijalnim prolaskom kroz neki izvor i kreiranjem XML konstrukcije kroz string. Krajnji rezultat tog procesa će biti jedan string koji će sadržati u sebi XML strukturu. Ovakav string možemo emitovati na izlaz standardno: Putem baferovanog upisa:
Poslednje dve metode ispisa su prilično linerane i ne vode računa o formatiranju izlaza, pa ukoliko želimo da XML bude uredno formatiran na izlazu, treba ručno da unesemo nove redove:
1
$redI = "" . $redIzvora . "\r\n";
Escape karakteri \n i \r označavaju novi red u tekstu. Ukoliko se koristi Windows operativni sistem, moraju biti uneta oba (n i r), ukoliko je operativni sistem Unix-olik, dovoljan je samo znak n, a ukoliko je sistem MacOS, dovoljan je samo r. Oba znaka rade na svim sistemima. Najvažnije iz lekcije: 1.
Prostori imena u XML-u služe za razdvajanje različitih struktura istog imena.
2.
Prostor imena definiše se atributom xmlns.
3.
Atribut za definiciju prostora imena nalazi se na elementu na koji se prostor imena odnosi ili na korenom elementu dokumenta.
4.
Moguće je definisati više različitih prostora imena na jednom korenom elementu dokumenta.
5.
Objekat tipa SimpleXMLElement je moguće snimiti u fajl metodom asXML("mojFajl.xml").
6.
Svi elementi u prostoru imena moraju biti označeni po sintaksi prostorImena:nazivElementa.
7.
Naziv xmlns atributa u definiciji XML prostora imena mora biti unikatan na nivou dokumenta.
DOM XML Jedinica: 6 od 11 DOM (Document Object Model) je jedan od načina tretiranja XMl i HTML dokumenata. U kontekstu DOM-a, cela XML struktura predstavlja se u obliku drveta, pri čemu se koren naziva dokument element (Document Element), svi njegovi podelementi nazivaju se deca nodovi (Child Nodes), braća nodovi (Siblings) i tekst nodovi (Text Nodes). Prvi podelement nekog elementa naziva se First Child, a poslednji Last Child. Umesto termina element, u DOM-u se upotrebljava termin nod (Node).
Iako su PHP i ostali serverski jezici opremljeni širokim asortimanom DOM programabilnosti, ovaj XML koncept primarno se upotrebljava na klijentskoj strani veb dokumenata. Svi moderni veb pretraživači definišu DOM strukturu učitanog HTML dokumenta i omogućavaju mu pristup putem klijentske skripte (JScript, JavaScript...). Sam DOM ima tri podkategorije, XML, HTML i CORE, od kojih ćemo u ovoj lekciji obraditi kategoriju XML. DOM ima daleko više metoda od SimpleXML-a. Ali su dosta ovih metoda standardne metode i neke od njih ćete sretati i u drugim jezicima. Na primer, JavaScript-u. DOMDocument objekat se kreira na sledeći način:
1
$xmlDom = new DOMDocument();
Zatim se u njega učitava XML dokument:
1
$xmlDom->loadXML($xmlString);
Ili
1
$xmlDom->load("mojFajl.xml");
Ukoliko dokument dolazi iz fajla. Kada jednom dođemo do dokumenta, lako dolazimo do elemenata (nodova):
Metoda getElementsByTagName kreira novi DOMElement objekat, koji u sebi sadrži nula ili više DOMElement objekata koji odgovaraju traženom parametru. Traženi parametar je u ovom slučaju naziv taga (knjiga). Svaki od dobijenih elemenata predstavljen je određenom pozicijom u item listi po sistemu baziranom na nuli (0prvi element, 1-drugi element...):
1
echo $knjiga->item(0)->nodeValue; //OVO JE PRVI ELEMENT
Ova linija vraća prvi element sa nazivom taga knjiga. To su svi podelementi ovog elementa, odnosno, autor i naslov, što će i biti emitovano na izlaz:
1
Petar Petrovic Petrova knjiga
Kada dođemo do željenog elementa, možemo istom tehnikom pretraživati taj element još dublje:
Vidimo da je svaki tekst nod naznačen atributom nodeValue. Ovaj atribut predstavlja sadržaj elementa, odnosno, tekst nod. Mogli smo takođe doći i do nekog od atributa dokumenta (u primeru knjige su imale atribute id i isbn). Da bismo dobili ove atribute, trebalo bi izmeniti drugi red prethodnog primera:
Kroz foreach petlju prolaze svi nodovi dokumenta, ali mi u telu petlje, prilikom svake iteracije proveravamo naziv noda. Ukoliko je naziv knjiga, pretražujemo odgovarajući atribut (isbn). Atribut (DOM objekta) koji sadrži naziv noda je nodeName:
1 2 3 4 5 6 7
$knjige = $xmlDom->getElementsByTagName("knjiga"); foreach($knjige as $knjiga) { $nodoviKnjige = $knjiga->childNodes; foreach($nodoviKnjige as $nod) echo $nod->nodeValue; }
Ako hoćemo malo bolju kontrolu kretanja kroz nodove, uz pomoć for petlje, na primer, verovatno je prva pomisao korišćenje sizeof ili count funkcija:
1 2
echo count($knjige); //NE RADI echo sizeof($knjige); //NE RADI
Ako isprobamo dve prethodne naredbe, videćemo da ne funkcionišu. To je zbog toga što jedna lista dom nodova nije pravi niz, pa nisu upotrebljive ni ove naredbe. Umesto njih, moramo koristiti DOMNode metod length:
1
echo $knjige->length;
Ovo je važno imati na umu, jer ni sizeof ni count neće izazvati greške prilikom izvršavanja, već će dati netačan rezultat, što može dovesti do logičke greške. Jednom kada dođemo do broja dece nodova jednog elementa, prolazak kroz njih je jednostavan:
Promenljiva $knjiga sadrži sve nodove prvog elementa, autora i naslov, ali i sam nod „knjiga”. Dakle, i sam nod je uzet u obzir:
1 2 3
0: knjiga 1: autor 2: naslov
Znajući ovo, podatke o autoru možemo dobiti na sledeći način:
1
echo $knjiga->item(1)->nodeValue;
Modifikacija XML dokumenta Saznali smo kako da pročitamo XML komponente. Pokušajmo sada da napravimo jedan:
1
$xmlDom = new DOMDocument();
Prvo ćemo definisati jedan DOMDocument objekat. Kada to uradimo, na način iz primera iznad, deklaracija našeg dokumenta će izgledati ovako:
1
Konstruktor DOMDocument objekta može prihvatiti i parametre. S obzirom na to da je naš prethodni dokument bio enkodiran pod unicode standardom (utf-8), postavićemo tu opciju i na novokreiranom dokumentu. Podatke o verziji i enkodingu možemo podesiti u konstruktoru objekta: Podatke o verziji i enkodingu možemo podesiti u konstruktoru objekta:
1
$xmlDom = new DOMDocument("1.0","utf-8");
Prvi parametar je verzija XML-a, a drugi kodni raspored. Zatim pravimo strukturu:
Za kreiranje jednog noda, koristimo metodu createELement(). Ona može prihvatiti jedan ili dva parametra. Ukoliko postavimo samo jedan parametar, taj parametar će predstavljati naziv noda. Ukoliko dodamo i drugi parametar, on će predstavljati sadržaj (vrednost) noda. Metodom appendChild() pridružujemo kreirani element dokumentu. Na isti način, kreiramo i ostale elemente:
Ono što može zbuniti, jeste to što se createElement metod uvek startuje na samom XML objektu, a ne na pojedinačnim elementima, ali ovo je pravilo DOM-a i funkcioniše kako na PHP XMLDOM-u tako i na DOM programabilnosti ostalih jezika. Pošto svaka knjiga ima podelemente autora i naslov, njih ćemo dodati istom metodom, sa tom razlikom što, umesto jednog parametra, prosleđujemo i drugi, sa sadržajem elementa:
Na isti način dodajemo i drugu knjigu. Prilikom dodavanja knjiga primećujemo obrazac. Takav obrazac se obično u produkciji izvršava kroz petlju. Ako bismo hteli da dodamo i atribute, mogli bismo to uraditi po sličnom principu:
Primećujemo metod createTextNode(). Njega upotrebljavamo ako ne želimo da vrednost dodelimo kroz metod createAttribute(). Cena je, naravno, nekoliko linija više. Kada završimo sa formatiranjem, dokument možemo emitovati na izlaz u vidu XML-a:
1
echo $xmlDom->saveXML();
ili u vidu HTML-a
1
echo $xmlDom->saveHTML();
I naravno, u fajl:
1
echo $xmlDom->save("mojFajl.xml");
Najvažnije iz lekcije: 1.
DOM XML funkcioniše po sistemu nodova.
2.
Koreni nod DOM XML-a je dokument.
3.
Osnovni objekat (dokument) DOM XML-a je $xmlDom = new DOMDocument();
4.
Učitavanje DOM XML dokumenta iz stringa vrši se metodom loadXML().
5.
Učitavanje DOM XML dokumenta iz fajla vrši se metodom load().
6.
Metoda za dodeljivanje podnodova određenog noda promenljivoj je getElementsByTagName().
7.
Svi podnodovi jednog noda nalaze se u atributu nod objekta pod nazivom childNodes.
8.
Metoda za preuzimanje atributa određenog noda je getAttribute().
9.
Naziv svakog noda, nalazi se u atributu nod objekta, pod nazivom nodeName.
10. Sadržaj svakog noda, nalazi se u atributu nod objekta pod nazivom nodeValue. 11. Lista svih podnodova jednog noda, nalazi se u atributu nod objekta item. 12. Dokument se emituje u string metodom saveXML(). 13. Dokument se emituje u fajl metodom save().
DOMXpath i SAX XML Jedinica: 7 od 11 Kada znamo kako funkcionišu DOM XML i XPath, ostaje samo da "sklopimo kockice" kako bismo rukovali XPath upitima kroz DOM. Potrebno nam je, zapravo, samo nekoliko naredbi:
1
$dom = new DOMDocument();
2
$dom->loadXML($xml);
3
$xpth = new DOMXPath($dom);
4
$knjige = $xpth->query("/izdanja/knjiga/autor");
Vidimo da se XPath upitima u DOM-u rukuje kroz poseban, DOMXPath objekat, koji prihvata DOMDocument objekat u konstrukciji. Kada pravilno formiramo DOMXPath objekat, možemo kreirati rezultate XPath upita kroz metod query. Nakon dobijanja rezultata, dobijenom objektu se obraćamo standardno. Na primer:
Rezultate DOMXPath objekta možemo dobiti na još jedan način: metodom evaluate. Ovaj metod očekuje, kao parametre, nod i relativnu putanju nodova koje želimo da prikažemo, a koji su ispod tog noda. Na primer, ako nod objekat sadrži /izdanja, onda bismo mogli kao parametre evaluate metoda proslediti taj nod i podupit /knjiga, čime bismo dobili sve knjige za aktuelni nod:
SAX (Simple API for XML) Način na koji smo do sada rukovali XML-om se u oba slučaja bazirao na učitavanju dokumenta, kreiranja objekta, odnosno, objekata, od tog dokumenta i preuzimanja određenih elemenata tih objekata kroz već formiranu strukturu. Na ovaj način imali smo veoma brzo preuzimanje podataka, jer je ceo dokument bio uvek učitan u neki objekat. Sa druge strane, usko grlo ovog pristupa bilo je samo učitavanje. Jer, ukoliko bi bio u pitanju veći dokument, morali bismo ga učitati kompletnog, pre nego što počnemo da ga obrađujemo. SAX podrazumeva drugačiji pristup. Dokument se čita sekvencijalno, i svaki element se obrađuje u hodu. Zato se SAX pristup naziva event based. SAX objekat kreiramo kroz XML parser set funkcija. Prvo nam je potrebna procedura (Handler), odnosno, sam dokument:
1
$sax = xml_parser_create();
Zatim, postavljamo callback funkcije za određene događaje koje želimo da obrađujemo. To mogu biti razni događaji, ali najbitniji su početak i kraj čitanja elementa, kao i unos sadržaja u element. Da bismo postavili callback funkciju za unos sadržaja, koristimo funkciju xml_set_character_data_handler. Ova funkcija prihvata dva parametra: SAX objekat (zapravo ovo je procedura na SAX resurs) i naziv callback funkcije:
1
xml_set_character_data_handler($sax, 'sadrzaj');
Kada postavimo adekvatnu proceduru, možemo početi sa čitanjem dokumenta, za šta koristimo funkciju xml_parse. Ova funkcija prihvata dva parametra: SAX objekat i sadržaj dokumenta (string):
1
xml_parse($sax, $xml);
Nakon završenog parsiranja, treba osloboditi resurse:
1
xml_parser_free($sax);
Ovaj primer, naravno, neće raditi bez odgovarajuće callback funkcije. Mi smo dali ime ovoj funkciji sadrzaj, a to znači da sada moramo napraviti i istoimenu funkciju:
1
function sadrzaj($sax, $data) {
2
echo $data; }
Funkcija sadrzaj emituje podatke na izlaz. Ukoliko bismo ostavili ovakav program, bili bi emitovani svi podaci. Zato ćemo napraviti filtriranje ubacivanjem još dve callback funkcije. Jednu za početak čitanja elementa i drugu za kraj čitanja dokumenta. Prvo ćemo definisati ove funkcije kao callback funkcije naredbom xml_set_element_handler:
1
xml_set_element_handler($sax, 'pocetak','kraj');
A zatim ćemo kreirati i same funkcije:
1
function pocetak($sax, $tag, $attr) {
2
global $nazivTaga;
3
$nazivTaga="";
4
if($tag=="NASLOV") $nazivTaga=$tag;
5 6
}
Funkcija za obradu početnog taga prihvata tri parametra: SAX objekat, element i atribute taga. U ovoj funkciji ćemo globalnoj promenljivoj naziv taga prosleđivati naziv aktuelnog taga, kako bi mogao da bude pročitan i iz drugih funkcija. Funkcija kraj ima dva parametra: SAX objekat i tag (element). Mi ćemo je koristiti samo da bismo, prilikom završetka čitanja svakog taga, resetovali vrednost promenljive nazivTaga (ovo smo, naravno, mogli uraditi i na početku funkcije pocetak):
} function sadrzaj($sax, $data) { global $nazivTaga;
17
if($nazivTaga=="NASLOV")
18 19
echo $data; }
Iz primera se vidi da SAX ima malo kompleksniji koncept čitanja, ali i veliku fleksibilnost. Zbog toga je najbolje, ukoliko želite da rukujete XML-om kroz ovaj koncept, krerati logiku u enkapsuliranoj strukturi.
Uvod u veb servise Jedinica: 8 od 11 Veb servisi su koncept koji omogućava kreiranje skalabilnih, multiplatformskih aplikativnih biblioteka, odnosno, samih aplikacija čija je karakteristika slaba povezanost, odnosno, udaljeno izvršavanje. Zamislimo da želimo da napravimo aplikaciju koja bi prikazivala televizijski program. Na primer, za 20 različitih kanala. Da bismo ovakvu aplikaciju opsluživali na dnevnom nivou, bilo bi nam potrebno da svakodnenvno kontaktiramo 20 različitih televizija i preuzimamo od njih programe, unosimo ih u aplikaciju i sl. Umesto toga, mogli bismo reći svakoj od televizija da nam pripremi program u nekom standardnom formatu, a zatim preuzimati tako pripremljen materijal i parsirati ga u našoj aplikaciji. Ovo bi znatno ubrzalo i standardizovalo proces. Ali, mogli
bismo otići i korak dalje, tako što ćemo tražiti da se i kompletno parsiranje i izvrši kod njih, a da nama samo kažu naredbe koje možemo koristiti kako bismo došli do tih informacija. Ovo, poslednje rešenje, prepoznaje se kao veb servis. Naravno, da bi veb servis stvarno to i bio, osim pomenute logike, mora posedovati još neke osobenosti. Pre svega, mora biti definisan kroz SOAP protokol (važi naravno samo za SOAP servise). SOAP (Simple Object Access Protocol) je baziran na XML-u i osnovno je sredstvo komunikacije između veb servisa i njegovog korisnika. Da li to znači da, kada pomenemo veb servis, zapravo mislimo na SOAP? U najvećem broju slučajeva - da. Iako postoje još neke vrste realizacije veb servisa, SOAP servisi su najzastupljeniji i simbolizuju ovu tehnologiju. Pošto je SOAP XML derivat, njegova forma je tekstualna, a ne binarna. To znači da, sve što šaljemo putem SOAP-a, može proći kroz HTTP protokol. Pored toga, HTTP protokol je nezavistan od platforme, pa se jedan servis može upotrebljavati na bilo kom sistemu u bilo kom programskom jeziku. I konačno, korišćenje HTTP protokola isključuje mogućnost da će preuzimanje podataka sa servisa biti onemogućeno Firewall-om. Kada pošaljemo zahtev veb servisu, on je upakovan u SOAP. Kada nam server pošalje odgovor, i on je takođe upakovan u SOAP. Drugi bitan element veb servisa je WSDL (Web Services Description Language). Ovo je opisni jezik veb servisa na osnovu koga je moguće ustanoviti šta servis radi i kako. Na osnovu WSDL-a, prilikom inicijalizacije servisa, u klijentskoj aplikaciji formiramo proxy objekat, koji će simulirati servis tokom kreiranja aplikacije. Na primer, imamo funkciju koja nam vraća kursnu listu iz banke. Ova funkcija je funkcija web servisa i možemo znati njeno ime i parametrizaciju samo ukoliko pregledamo opis servisa, odnosno, njegov WSDL dokument. Treći sastavni deo XML veb servisa je UDDI (Universal Description Discovery and Integration). To je sistem za indeksiranje, odnosno, pretragu različitih veb servisa u mreži. S obzirom na to da servisi nisu nešto što je moguće pronaći konvencionalnim metodama (pretragom uz pomoć pretraživača), koriste se veb direktorijumi sa informacijama o veb servisima. Svaki servis u ovom sistemu predstavljen je UDDI XML deskripcijom.
Priprema za rad Da bismo napravili veb servis u PHP-u, koristićemo biblioteke php_soap.dll i php_xmlrpc.dll. Biblioteka php_soap.dll se još uvek smatra eksperimentalnom bibliotekom i zbog toga nije podrazumevano aktivirana (mada zavisi koju distribuciju PHP-a koristite). Takođe, ni biblioteka php_xmlrpc.dll nije podrazumevano aktivirana. Da bismo aktivirali ovu ekstenziju, editujte php.ini fajl i odkomentarišite sledeće dve linije (brisanjem oznake ; ispred redova):
1 2
;extension=php_soap.dll ;extension=php_xmlrpc.dll
Aktivaciju ekstenzija moguće je izvršiti i iz wamp manager-a, tako što ćete aktivirati opciju PHP settings > PHP extensions, a zatim odabrati željene ekstenzije.
Jedna od osnovnih klasa php_soap ekstenzije je SoapServer, pa možete proveriti da li je ekstenzija dobro učitana proverom postojanja ove klase:
1
echo class_exists('SoapServer');
Funkcija class_exist vraća boolean tip, pa će, ako je ekstenzija validno učitana, ova linija koda rezultirati ispisom broja 1 na strani. Pored SOAP servisa, među poznatijim servisima nalaze se i RPC i REST veb servisi. Najvažnije iz lekcije:
1.
Postoje tri ključne reči koje identifikuju SOAP veb servis: SOAP,WSDL i UDDI.
2.
SOAP čini formu servisa. U dolaznom SOAP XML dokumentu nalazi se parametrizovani zahtev, dok se u odlaznom SOAP XML dokumentu nalaze podaci.
3.
WSDL je opis servisa. On sadrži informacije o tome šta i kako servis radi.
4.
UDDI je deskripcija servisa za prezentovanje u uDDI sistemu indeksiranja.
5.
Da bi veb servis mogao da radi u PHP-u, potrebna mu je ekstenzija php_soap.dll.
6.
Servisi za komunikaciju koriste HTTP protokol.
7.
Veb servisi omogućavaju prenos podataka bez obzira na bezbednosna ograničenja (Firewall).
SOAP Jedinica: 9 od 11 SOAP je skraćenica od Simple Object Access Protocol. Postoje dva oblika SOAP dokumenta: request i response. Oba, naravno, vezana za istoimenu HTTP akciju. Kada dođe do SOAP request-a, serveru se prosleđuje standardno HTTP request zaglavlje sa SOAP request-om u prilogu. Ali, ovo ne znači da je SOAP vezan isključivo za HTTP. SOAP je moguće prenositi i putem drugih protokola (smtp, ftp...). Priključivanje SOAP dokumenta nekom protokolu nazivamo SOAP Binding. Evo jednog primera HTTP SOAP request-a:
Vidimo nekoliko osobenosti. Prvo, metod slanja je post. Ovo je pravilo u SOAP HTML bindingu. Takođe, vidimo atribut SOAPAction. To je metoda samog servisa, koja se poziva kroz request. U primeru, naziv metode je: GetCurrentExchangeRates U telu SOAP HTTP request-a nalazi se SOAP request dokument:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
stringstringlongdecimal
Sadžaj dela telo SOAP envelope elementa ima sopstvenu strukturu koja nije strukturalno vezana za sam envelope. Može čak imati i sopstveni prostor imena. Na primer:
1 2 3 4 5
Beograd
Primer opisuje metod PrognozaZaGrad, koji prihvata parametar Grad. Response (odgovor) servisa takođe sadrži HTTP i SOAP delove. HTTP zaglavlje sadrži poruku (statusni kod) servera (200-299, ako je sve u redu), dok telo sadrži SOAP (XML) dokument. Ovaj SOAP dokument ima istu strukturu kao i request, s tim što sadrži izlazne podatke, odnosno, rezultat zahteva. Jedan od opcionih elemenata SOAP dokumenta, odnosno, njegovog Body taga je Fault element. Ovaj element sadrži informacije o grešci, ukoliko do nje dođe prilikom procesiranja zahteva na serveru. Ova poruka biće aktivirana, ukoliko je statusni kod HTTP odgovora 500-599:
WSDL (Web Services Description Language) Iako ima dosta informacija, SOAP najčešće nećemo pisati ručno. Ovo je nešto što će za nas raditi SOAP klase. U PHP-u, ove klase nalaze se u SOAP biblioteci - php_soap. Isto važi i za WSDL dokumente. I njih ćemo najčešće definisati uz pomoć okruženja. Pogledajmo ipak šta čini strukturu WSDL dokumenta. Kao i SOAP, i WSDL dokument je tipa XML i kao i kod svakog specijalizovanog XML tipa, postoje neka pravila. Koreni element WSDL dokumenta je definitions element i on podrazumeva četiri tipa podelemenata: portType,bindings, message i service. portType opisuje funkcije servisa. Odnosno, sve što on može da radi. Svaka funkcija servisa nalazi se u podelementu operation i sadrži naziv i odlaznu i dolaznu poruku (message). Odlazna i dolazna poruka nisu obavezne komponente operation elementa, jer osim request-response, operation može biti i nekog drugog tipa (one-way, solicit-response, notification):
1 2 3 4 5 6
Operatoion u primeru sabira brojeve, što znači da će nam biti potrebna dva ulazna parametra (za operande) i jedan izlazni parametar (za rezultat). Detalji o ovim parametrima nalaze se u posebnim podelementima korenog elementa koji se nazivaju message. U primeru imamo dva seta parametara, ulazne i izlazne i zato koristimo i dva message elementa:
1 2 3 4 5 6 7
Svaki element message sadrži podelemente part i type, koji respektivno predstavljaju naziv i tip parametra. Takođe, svaki message element ima i atribut name, koji predstavlja naziv elementa (uz pomoć koga je identifikovan u portType-u). Podaci najvišeg nivoa o servisu, nalaze se u elementu service. Naziv servisa, naziv porta, binding i sama adresa SOAP servera:
1 2 3 4 5
Konačno, deo u kome su povezane sve komponente servisa i WSDL-a. Element binding:
Definicija veb servisa nalazi se u WSDL dokumentu.
2.
Priključivanje SOAP dokumenta nekom protokolu naziva se SOAP Binding.
3.
Koreni element SOAP objekta je envelope.
4.
Svaki SOAP dokument sadrži obavezno body i opciono header.
5.
Koreni element WSDL dokumenta naziva se definitions.
6.
SOAP se najčešće prenosi HTTP protokolom.
7.
Fault element je deo SOAP dokumenta koji sadrži poruku u slučaju greške.
Kreiranje SOAP i RPC veb servisa Jedinica: 10 od 11
Kreiranje SOAP servisa Da bi veb servis bio funkcionalan, potreban nam je WSDL dokument, odnosno, opis servisa i skripta (program) koji će taj servis eksponirati. WSDL za servis sabiranje već imamo iz prethodne lekcije mojOpis.wsdl.
Osnovni objekat za rukovanje veb servisom je SoapServer objekat. Prilikom instanciranja, konstruktoru se prosleđuje opis servisa – wsdl document:
1
$server = new SoapServer("mojOpis.wsdl");
Sledi opis funkcionalnosti servisa. Funkcije koje smo definisali u WSDL dokumentu, sada moramo kreirati i definisati i u pozadinskom kodu:
1
$server->addFunction("sabiranje");
Koristimo metod addFunction, kako bismo pridružili funkciji iz WSDL-a funkciju na serveru. Zatim, neophodno je da napravimo i istoimenu funkciju u pozadinskom kodu:
1
function sabiranje($a, $b) { return $a + $b; }
Konačno, potrebno je da aktiviramo ceo proces. To radimo metodom handle, SoapServer objekta. Ovo je metod koji, u stvari, procesira ceo servis i prosleđuje ga klijentu:
1
$server->handle();
Praksa je da se pre čitanja WSDL dokumenta isključi SOAP keš, kako se ne bi uvek učitavala ista definicija servisa:
1
ini_set("soap.wsdl_cache_enabled", "0");
Kompletan kod servisa izgleda ovako:
1 2 3 4 5 6
function sabiranje($a, $b) { return $a + $b; } ini_set("soap.wsdl_cache_enabled", "0"); $server = new SoapServer("mojOpis.wsdl"); $server->addFunction("sabiranje"); $server->handle();
Pristup SOAP servisu Napravljeni servis moguće je čitati sa bilo koje platforme i iz bilo kog programskog jezika. Tako je i servis koji smo napravili u prethodnom primeru, dostupan bilo kom sistemu. U PHP-u, za pristup ovom servisu dovoljne su nam dve linije koda. U prvoj inicijalizujemo objekat klase SoapClient a u drugoj pozivamo metod servisa:
1 2
$klijent = new SoapClient("mojOpis.wsdl"); echo $klijent->sabiranje(3,4);
Ovaj kod prikazaće rezultat sabiranja brojeva 3 i 4.
Listu svih metoda servisa možemo dobiti funkcijom __getFunctions:
1
print_r($klijent->__getFunctions());
XML-RPC Osim SOAP veb servisa, u PHP-u je moguće ostvariti i XML-RPC veb servise. Koncepcija je slična. Takođe funkcioniše po sistemu servera i klijenta, ali je sama struktura zahteva i odgovora nešto jednostavnija. Kreiranje XML-RPC servisa Da bismo kreirali XML-RPC servis, potrean nam je serverski objekat, odnosno, resurs:
1
$server = xmlrpc_server_create();
Nakon kreiranog servera, definišemo callback funkcije, poput onih u SOAP servisu:
Ovo radimo kroz xmlrpc_server_register_method funkciju, pri čemu su parametri funkcije respektivno procedura za server, metoda servisa i funkcija servisa. Metoda servisa je ono što će biti viđeno spolja (na klijentu), dok je funkcija servisa funkcija koja će opsluživati tu metodu iznutra (na samom serveru). Sledeće, potrebno je da preuzmemo prosleđene podatke. Oni se nalaze u promenljivoj$HTTP_RAW_POST_DATA. Može se dogoditi da ova promenljiva nije dostupna. U 99% slučajeva uzrok ovome je sledeće setovanje u php.ini fajlu:
1 2
; Always populate the $HTTP_RAW_POST_DATA variable. always_populate_raw_post_data = Off
Potrebno je promeniti setovanje u:
1
always_populate_raw_post_data = Off
Nakon toga, formiramo response promenljivu na osnovu rezultata callback funkcije. To radimo sledećom funkcijom:
Kada imamo rezultat, potrebno je samo da ga emitujemo na izlaz i zatvorimo server:
1 2
print $response; xmlrpc_server_destroy($server);
Naravno, podrazumeva se da je funkcija definisana na početku koda. Naša funkcija će sabirati dva broja. Od parametara funkcije, za nas je bitan drugi parametar, koji sadrži parametre koji su došli u pozivu rpc metode. Ovi parametri su u nizu, pa ih tako i tretiramo u telu funkcije. Pošto nam treba sabiranje parametara, obraćamo im se sa $parametri[0] i $parametri[1] što će biti prva (i jedina) dva parametra poziva:
1
function sabiranjeFunkcija($metod, $parametri) { return array($parametri[0] + $parametri[1]); }
Pristup XML-RPC servisu Da bismo pristupili XML-RPC servisu, potrebno je da: napravimo (serijalizujemo) XML-RPC zahtev, smestimo taj zahtev u kontekst Http zahteva, pročitamo rezultat servisa na prosleđeni zahtev i deserijalizujemo rezultat. Prvo, serijalizujemo zahtev:
Funkcija xmlrpc_encode_request, na osnovu parametara, napravila je XML-RPC zahtev i prosledila ga promenljivoj $request. Taj zahtev, sa navedenim parametrima, izgleda ovako:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
sabiranje24
Zatim pravimo listu Http parametara, koje ćemo proslediti tokom poziva servisa. U ovu listu smeštamo i kreirani zahtev:
Odgovor na poziv iz primera, trebalo bi da izgleda ovako:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
6
Da bismo ovakav rezultat vratili u čitljivu formu, izvršavamo nad njim funkciju xmlrpc_decode:
1
$response = xmlrpc_decode($res);
Nakon ovoga, promenljiva response sadržaće povratni parametar funkcije (niz):
1
print($response[0]);
Eventualno možemo proveriti rezultat pre emitovanja funkcijom xmlrpc_is_fault() koja prihvata niz kao parametar (zbog čega i prosleđujemo niz kao rezultat funkcije:
1 2 3
if ($response && xmlrpc_is_fault($response)) { trigger_error("Greska!"); } else { print($response[0]);
Za kreiranje SOAP server objekta koristimo klasu SoapServer.
3.
Pristup SOAP servisu vrši se klasom SoapClient.
4.
XML-RPC server kreira se funkcijom xmlrpc_server_create.
5.
XML-RPC server prihvata samo validno serijalizovan zahtev.
6.
Za serijalizaciju XML-RPC zahteva koristimo funkciju xmlrpc_encode_request .
7.
Da deserijalizujemo odgovor na XML-RPC zahtev koristimo funkciju xmlrpc_decode.
REST veb servisi Jedinica: 11 od 11 Representational State Transfer (REST) predstavlja koncept u kome jedinstveni URL-ovi domena predstavljaju, zapravo, objekte kojima upravljamo kroz HTTP metode. Kao i kod ostalih servisa. I za rest važi pravilo platformske i jezičke nezavisnosti i otpornosti na Firewall. Iz prostog razloga, što je jedini protokol koji REST koristi, HTTP. Za razliku od SOAP-a i RPC-a, REST ne zahteva posebne XML Wrapper-e. Logično, jer su objekti reprezentovani URL-ovima, a metode HTTP metodama (PUT, GET, POST, DELETE): http://www.mojDomen.com/sabiranje?a=2&b=3 Odgovor se, takođe, prosleđuje HTTP protokolom, pri čemu sam format (XML, JSON...) nije relevantan. PHP nema ugrađenu funkcionalnost za rukovanje REST servisima, što znači da se mora koristiti eksterna ili stvoriti sopstvena. Da bismo shvatili REST logiku, radićemo „ručno”.
REST koncept koristi URL-ove za reprezentaciju objekata i HTTP metode za rukovanje njima. GET za preuzimanje podataka, POST za kreiranje novih podataka, PUT za ažuriranje podataka i DELETE za brisanje podataka. Pogledajmo kako bismo REST-om rešili rukovanje jednim nizom podataka (naravno niz ovo će biti Stateless operacije i niz neće moći da ostane):
Ovaj kod će prikazati niz svih podataka za jedan grad. Mogli bismo proveriti get parametre i u odnosu na njih prikazati podatke samo za određenu državu:
Ako bismo želeli da unesemo novu vrednost u niz, koristili bismo metod POST. Za sada ćemo samo obraditi zahtev, a nešto kasnije ćemo videti i kako da ga napravimo (naravno, post zahtev uvek možemo napraviti putem forme, ali u tom slučaju gubi se koncept servisa). Nakon provere get metode, vršimo proveru POST metode:
Za ažuriranje, koristi se HTTP metoda PUT. Ova metoda se retko koristi van konteksta REST-a. Njena svrha je premeštanje fajlova na server. Ali, za razliku od POST metode, koja premeštani sadržaj transportuje i skladišti kao binarnu formu, uz pomoć koje posle sam server (odnosno, programer putem serverske skripte) određuje kako će ta forma biti tretirana, PUT rukuje fajlovima direktno i smešta ih na lokaciju naznačenu u zahtevu. Odmah je jasno da ovo može da bude veoma opasno. Zbog toga je transport fajlova PUT metodom najčešće onemogućen kod javnih hosting provajdera. Podaci poslati put metodom nalaze se u strimu php://input, pa ih možemo obraditi na sledeći način:
4 5 6 7 8 9 1 //Razbijamo parametre na ključeve i vrednosti 0 $kvParovi = explode("&", $parametri); 1 $rez = array(); //kreiramo listu ključeva i vrednosti 1 foreach($kvParovi as $kvPar) 1 { 2 $par = explode("=",$kvPar); 1 $kljuc = $par[0]; $vrednost = $par[1]; 3 $rez[$kljuc]=$vrednost; 1 4 } 1 //Vršimo izmenu podataka 5 $podaci[$rez['drzava']] = 1 array("GlavniGrad"=>$rez['GlavniGrad'],"Kontinent"=>$rez['Kontinent']); //Vraćamo rezultat na izlaz 6 print_r($podaci); 1 } 7 1 8 1 9 2 0
DELETE HTTP metod možemo da koristimo za brisanje. U našem slučaju, obrisaćemo element iz liste. Parametre možemo proslediti (i preuzeti) kroz URL string, pa je jedino važno da proverimo HTTP metod. Ukoliko je metod DELETE, vršimo brisanje po ključu prosleđenom kroz URL:
Sada je pravi trenutak da kažemo nešto o rezultatu, odnosno, odgovoru servera na određeni REST zahtev. Do sada, naši odgovori bili su sirovi Dump-ovi nizova, što, iako je dobro za testiranje, nije dobra produkciona praksa. Pravilan odgovor servera, bio bi adekvatno zaglavlje, sa statusnom informacijom (200,201,202....) i podaci serijalizovani nekom prepoznatljivom serijalizacijom. Pod „Prepoznatljivom serijalizacijom” mislimo pre svega na na XML ili JSON. Poruku možemo poslati putem funkcije zaglavlja. Na primer:
1
header("HTTP/1.1 200 Sve je u redu");
ili
1
header("HTTP/1.1 401 Greška u autorizaciji!");
odnosno:
1 2 3 4 5 6 7 8 9 10 11
if($metod=="delete") { if(isset([$_REQUEST['drzava'])) { unset($podaci[$_REQUEST['drzava']]); header("HTTP/1.1 200 Sve je u redu"); print_r($podaci); } else header("HTTP/1.1 500 Greška!"); }
Klijent Kada je u pitanju dobijanje informacija putem REST tehnologije, susrećemo se sa „iskonskim” problemom parametrizacije HTTP zahteva kroz zaglavlje. Ukoliko bismo želeli da dobavimo informaciju sa servisa, putem get metode, jednostavno bi trebalo poslati zahtev sa parametrima u URL-u. Ali, šta ako hoćemo da pošaljemo post zahtev, ali da pri tom on ne bude realizovan kroz formu? Ili, ukoliko hoćemo da izvršimo get ili post zahtev, a da pri tom ne izvršimo redirekciju strane? Tada možemo iskoristiti socket stream. Socket strim funkcioniše isto kao i file stream. Prvo definišemo resurs procedurom funkcijom fsockopen, koja prihvata host i port strima (zapravo, host na kome se nalazi dokument koji hoćemo da strimujemo:
Ove podatke treba da isparsiramo kako bismo dobili traženi informacije. Prvo ćemo kompletan odgovor podeliti na dva dela:
1
$rez = explode("\r\n\r\n", $response);
Presecamo tekst odgovora u delu gde se pojavljuju dva nova reda, a to je baš deo između zaglavlja i tela. Nakon ovoga, u promenljivoj $rez imamo kompletno zaglavlje kao prvi član i telo kao drugi član. Zaglavlje zatim opet možemo izdeliti na članove, kako bismo izvukli informaciju o statusu:
1
$responseZaglavlje = explode("\r\n",$rez[0]);
Sada se informacija o statusu nalazi u prvom članu promenljive $responseZaglavlje.
Kompletno telo, nalazi se u prvom članu promenljive (niza) $rez:
1
$responseTelo = $rez[1];
Po istom principu, možemo aktivirati i ostale HTTP metode zahteva, pa bi kod klijenta i servera do sada mogao izgledati ovako: Napomena: ovo nije primer potpunog koda, već samo prikaz sistema. Primeru nedostaju razne komponente, pre svega, bezbednosne.
JSON U primerima, rezultate servisa smo vraćali kroz print_r naredbu. Ovako nešto, naravno, nećemo raditi u produkciji, već ćemo koristiti neki od standardnih tipova serijalizacije. Jedan od njih je, svakako XML. Iz uvodnog dela ovog kursa naučili smo dosta o XML-u i prilično bi nam jednostavno bilo da dobijene odgovore iz primera serijalizujemo u ovom jeziku. Drugi, naročito popularan način serijalizacije je JSON serijalizacija. Ovo je serijalizacija koja je veoma popularna u JavaScript-u (o čemu dovoljno govori njen pun naziv Java Script Object Notation) i često se koristi za komunikaciju između AJAX klijentskih objekata i serverskih dobavljača. JSON je strukturalno veoma jednostavan. Kako za čitanje, tako i za pisanje. On poznaje dva generalna formata u kojima skladišti podatke: niz i objekat. Kada su podaci u formi objekta, onda je to, zapravo, niz ključeva i parova oivičen vitičastim zagradama. Na primer:
1
niz "drzava"=>"Srbija", "glavniGrad"=> "Beograd" biće u JSON notaciji prikazan kao: {"drzava":"Srbija","glavniGrad":"Beograd"}
PHP ima ugrađene funkcije za rukovanje JSON notacijom. To su funkcije json_encode i json_decode. Ako bismo želeli da pretvorimo neke podatke (niz) u JSON, napisali bismo jednostavno: $jsonObjekat = json_encode($niz);i dobijeni objekat ($jsonObjekat) zatim dalje tretirali kako nam odgovara (najčešće je to slanje do nekog konzumenta).
Prilikom čitanja, dobijeni podatak dekodiramo funkcijom json_decode, i prosleđujemo promenljivoj:
Funkcija json_decode vraća niz, pa tako i dekodirani objekat tretiramo kao i bilo koji drugi niz:
1
print_r($dekodiraniJsonObjekat);
cURL U većini implementacija PHP nudi i dodatnu biblioteku za rukovanje zahtevima, transportom informacija, preuzimanjem i slanjem dokumenata i sl. Ova biblioteka naziva se libcurl i predstavlja bibliotečku reprezentaciju aplikacije cURL. cURL (client URL-s) je naročito koristan ukoliko želimo da kreiramo sopstvene HTTP zahteve i odgovore jer korisnika oslobađa rukovanja socket strimovima, zaglavljima i sl. cUURL (libcurl) najčešće je potrebno eksplicitno aktivirati u PHP-u učitavanjem ekstenzije. (php_curl.dll). Jedan cURL proces podrazumeva nekoliko koraka. Inicijalizaciju, podešavanje opcija, startovanje procesa i preuzimanje rezultata i zatvaranje. Evo kako bi izgledao jedan najjednostavniji cURL proces:
1 2 3 4 5 6 7 8 9
//inicijalizacija $ch = curl_init(); //podešavanje opcija curl_setopt($ch, CURLOPT_URL,'http://www.google.com'); //startovanje i preuzimanje rezultata $rezultat = curl_exec ($ch); //zatvaranje curl_close ($ch); //prikazivanje rezutata nije sastavni deo procesa echo $rezultat;
Iz primera se vidi da je jedino zapravo bitno poznavati opcije. Pogledajmo, na primer, koliko bi jednostavno bilo dozvati naš servis, post metodom uz pomoć cURL-a:
1 2 3 4 5 6 7 8 9 10
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL,'http://localhost/server.php'); //aktivira se post metod (opcije se podešavaju po sistemu ključa i vrednosti //ključ je naziv opcije (drugi parametar), a treći parametar je vrednost) curl_setopt($ch, CURLOPT_POST, 1); //Često je potrebno podesiti i više opcija u ovom slučaju, trebaju nam i post parametri curl_setopt($ch,CURLOPT_POSTFIELDS, "drzava=kina&GlavniGrad=Peking&Kontinent=Azija"); $rezultat = curl_exec ($ch); curl_close ($ch); print_r($rezultat);
Evo liste važnijih cURL opcija:
CURLOPT_COOKIE (tekst) Sadržaj kolačića koji se prosleđuje kroz HTTP zaglavlje.
CURLOPT_COOKIEFILE (putanja fajla) Naziv fajla koji sadrži kolačić koji se prosleđuje kroz HTTP zaglavlje.
CURLOPT_CRLF (1,0) Aktivira konverziju UNIX oznake za nove redove u oznaku CR/LF.
CURLOPT_FAILONERROR (1,0) Prekid operacije ukoliko je status odgovora veći od 300 (greška).
CURLOPT_FILE (fajl hendler) Izlaz cURL rezultata. Standardno je strana (STDOUT), ali može biti i bilo šta drugo. Npr. fajl. U tom slučaju, kao parametar se navodi fajl procedura.
CURLOPT_FOLLOWLOCATION (1,0) Ukoliko je aktivno, cURL će se redirektovati na adresu iz Location atributa u zaglavlju (ukoliko taj atribut postoji).
CURLOPT_FTPAPPEND (1,0) Dodaje sadržaj na već postojeći fajl putem FTP-a. Ako je neaktivno, fajl će biti prepisan
CURLOPT_FTPLISTONLY (1,0) Redukovana lista podataka sa FTP servera (samo nazivi fajlova, bez detalja).
CURLOPT_HEADER (1,0) Uključuje zaglavlje u izlaz.
CURLOPT_HTTPHEADER (niz) Lista atributa zaglavlja.
CURLOPT_INFILE (fajl hendler) Putanja ulaznog fajla, ukoliko šaljemo fajl.
CURLOPT_INFILESIZE Veličina ulazog fajla.
CURLOPT_MAXREDIRS Maksimalan broj redirekcija iz primljene lokacije atributa koje cURL može izvršiti.
CURLOPT_NOBODY (1,0) Onemogućavanje slanja tela u HTTP zahtevu.
CURLOPT_POST (1,0) Aktivira cURL POST zahtev.
CURLOPT_POSTFIELDS (parametri) Parametri POST zahteva.
CURLOPT_REFERER (naziv referera) Naziv referera.
CURLOPT_RESUME_FROM Pozicija (u bajtovima) od koje želimo da započnemo transfer.
CURLOPT_RETURNTRANSFER (1,0) Podaci iz transfera se prosleđuju kao rezultat umesto emitovanja na izlaz.
CURLOPT_STDERR (putanja fajla) Fajl u koji se loguju greške.
CURLOPT_TIMEOUT (broj sekundi) Vreme čekanja na izvršenje cURL operacije.
CURLOPT_UPLOAD (1,0) Priprema određeni fajl za ažuriranje.
CURLOPT_URL (adresa) Adresa sa koje će cURL preuzeti podatke.
CURLOPT_USERPWD Šifra koju, ako je potrebno, cURL prosleđuje udaljenom serveru.
CURLOPT_USERAGENT Naziv User-agent-a koji će biti prosleđen u zahtevu.
CURLOPT_VERBOSE (1,0) Loguje (emituje na izlaz) svaku akciju u procesu, koju je u stanju da identifikuje.
CURLOPT_WRITEHEADER (naziv fajla) Fajl u koji će biti uneto zaglavlje rezultata
Najvažnije iz lekcije: 1.
REST podrazumeva URL-ove za reprezentaciju objekata.
2.
REST rukuje objektima putem HTTP metoda.
3.
HTTP metode koje se koriste u REST-u su uglavnom GET, POST, PUT i DELETE.
4.
Standardna funkcionalnost HTTP metoda u REST-u je: GET – prikaz podataka, POST-unos podataka, PUT-ažuriranje podataka i DELETE-brisanje podataka.
5.
JSON je način/jezik serijalizacije podataka.
6.
PHP ima ugrađene funkcije za rukovanje JSON-om, json_encode i json_decode.
7.
Dobar način slanja povratnih podataka iz servisa je u serijalizovanoj formi.