Andmebaas veebilehestiku juures Nagu eelnenud näidetest näha, pole veebi koostamisel andmebaas sugugi hädavajalik lisandus. Küll aga võimaldab veebilehe andmebaasitabeliga ühendamine mitmete toimetustega mugavamal ja/või ohutumalt hakkama saada. Hulk võimalusi, mis muidu tuleks ise kodeerida, on juba andmebaasiprogrammidesse sisse ehitatud. Tüüpilised kohad, kus andmebaaside eelised välja tulevad on järgmised: * samas veebilehestikus kasutatavad mitmesuguse struktuuriga seotud andmed * otsing parameetrite järgi * andmete muutmine veebi kaudu - eriti mitme administraatori korral Eelnevalt nähtud suhteliselt staatilised lehed seega, kus kasutatakse lihtsalt ühiseid päiseid ning sarnase struktuuriga pikematekstilisi andmeid - selliste lehtede puhul pole andmebaas sugugi hädavajalik. Kui aga soovida veebi kaudu muudetavat/täiendatavat lehestikku teha, siis on andmebaasi abi kindlasti omal kohal. Enne näite juurde minemist märgime siia edaspidi kasutatavad mõisted. * Andmebaasiprogramm, andmeohjur - masinasse installeeritud programm või draiver andmebaasidega ümber käimiseks. Nt. MySQL, Oracle, PostgreSQL, Access. * Andmebaas - andmeohjuri poolt hallatav tabelite komplekt. Nt. konkreetse veebipoe jaoks tarvilikud andmetabelid. Ühes masinas võib olla (enamasti ongi) mitu andmebaasi. Igas andmebaasis saab olla palju andmetabeleid. Ühe andmebaasi piires on eri andmetabelitest andmeid mugavam/kiirem siduda kui eri andmebaaside vahel. * Andmetabel - ridade ja veergudega andmete hoidmise koht. Igal veerul ehk tulbal on nimi ja tüüp - nt. tekst, kuupäev, täisarv, reaalarv. * SQL - tõenäoliselt levinuim keel andmebaasile käskude andmiseks. Selle abil saavad andmebaasiga suhelda nii inimesed kui andmebaasivälised rakendusprogrammid (nt. PHP). Inimeste jaoks tehakse vahel ka graafilisi haldusvahendeid, kuid teised programmid suhtlevad üldjuhul andmebaasiga SQLi kaudu. Siinses õppematerjalis kasutame andmebaasina MySQLi. Ta sobib PHPga hästi kokku, kuna on suunatud enamvähem sarnasele sihtgrupile: lihtsamate veebirakenduste lihtne loomine tasuta tarkvara abil. Eestis vähemasti 2009nda aastani tõenäoliselt levinuim moodus veebirakenduste loomiseks. (Üli)suurtes süsteemides nagu nt. pangalehed jääb vahenditesse sisseehitatud kontrolle ja stuktueeritust väheks. Aga enamike veebirakenduste nagu foorumid, uudistelehed, registreerumisvormid jaoks on võimalusi piisavalt. Arendamine ja ülespanek nõuab riistvaraliselt vähe ressursse, lehtede ülespanekuks kasutatavaid teenusepakkujaid (nt zone.ee, elkdata.ee) on piisavalt. Täiesti korraliku PHP ja MySQLi veebimajutuse leiab 2009nda aasta seisuga alates 100st kroonist kuus. Ühe andmetabeliga seotud veebilehestik MySQLis ja ka teistes relatsioonilistes ehk tabelipõhistes andmebaasides hoitakse ja väljastatakse pea kõiki andmeid tabelitena. Ning viimastel aastakümnetel üle ¾ andmebaasidest ongi relatsioonilised. Andmebaasis toimetamiseks peab kõigepealt sellesse sisenema. Oma arvutisse nt. XAMPP abil veebiloomiskomplekti installides on MySQL kohe kättesaadav. Avalikumas serveris tuleb sisenemiseks enne administraatorilt kasutajakonto paluda. Ning mõnes teenusepakkuja keskkonnas saab ligi vaid graafilise kasutajaliidese (nt. PHP MyAdmin) kaudu. Käsurealt sisenemine näeb välja ligukaudu järgmine. Võti -ujaagup näitab, et kasutajaks (user) on jaagup. Järgmine jaagup tähistab andmebaasi nime. Ning -p teatab, et parool küsitakse eraldi nõnda, et selle tähti ekraanile ei kuvata. Kui kõik õnneks läheb, siis ilmub lõpuks ette käsuviip mysql > jaagup@tigu:~$ mysql -ujaagup jaagup -p Enter password: Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 47574 Server version: 5.0.51a-24+lenny2-log (Debian) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> Tabeli loomiseks käsklus CREATE TABLE. Käsu nimele järgneb tabeli nimi (praegusel juhul "lehed"). Ning siis sulgudes komadega eraldatuna tulpade nimed ning nende parameetrid. Iga tabeli esimeseks tulbaks on üldjuhul id - identifikaator, mille abil hiljem ridu eristada ja neile viidata. Parameetrid võivad lihtsamate rakenduste puhul enamasti samaks jääda. Selgitused: INT - täisarv NOT NULL - väärtus ei tohi puududa AUTO_INCREMENT - server arvutab lisamisel ise juurde sobiva seni veel kasutamata väärtuse PRIMARY KEY - selle tulba väärtust kasutatakse edaspidi tabeli vastavale reale viitamisel (näiteks muutmise või kustutamise juures). Tulp pealkiri siin näites tüübiga VARCHAR(50) ehk siis tekst pikkusega kuni 50 tähte. Sisu tüübiks TEXT, mis tähendab, et pikkust ei piirata. Kokku siis lause järgmine, mis tasub valmis kirjutada ning MySQLi käsuviibale kopeerida: CREATE TABLE lehed( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, pealkiri VARCHAR(50), sisu TEXT ); Kui vastuseks tuli Query OK, siis järelikult ettevõtmine õnnestus. Muidu tuleb veateateid uurida ja uuesti proovida. Andmete lisamiseks on loodud käsklus INSERT INTO. Järgneb tabeli nimi, siis sulgudes tulpade nimed kuhu lisatavad andmed tulevad. Edasi sõna VALUES ning sulgude sisse komadega eraldatult igale tulbale vastav väärtus. Tekstilised andmed paigutatakse ülakomade vahele. INSERT INTO lehed (pealkiri, sisu) VALUES ('Ilmateade', 'Kuiv ilm'); Tahtes rohkem andmeid lisada, tuleb INSERT lauset lihtsalt mitu korda käivitada, igal korral eraldi andmed sisse pannes. mysql> INSERT INTO lehed (pealkiri, sisu) VALUES ('Korvpall', 'Treening reedel kell 18'); Query OK, 1 row affected (0.00 sec) Kui mõned sees, siis on hea vaadata ja kontrollida, et mis sinna täpsemalt sai. Andmete küsimiseks on SQLis loodud käsklus SELECT. Tärn tähendab, et kuvatakse kõikide olemasolevate tulpade andmed. Sõnale FROM järgneb tabeli nimi ning käsu lõppu käivitamiseks semikoolon. Lehtede tabeli sisu tuleb siis välja järgnevalt. mysql> SELECT * FROM lehed; +----+-----------+-------------------------+ | id | pealkiri | sisu | +----+-----------+-------------------------+ | 1 | Ilmateade | Kuiv ilm | | 2 | Korvpall | Treening reedel kell 18 | +----+-----------+-------------------------+ 2 rows in set (0.00 sec) Nagu näha, id-väärtused on automaatselt ise pandud, kuna vastaval tulbal on juures omadus AUTO_INCREMENT. Tahtes andmeid veel juurde panna, tuleb taas käivitada INSERT-lause sobivate andmetega. Teksti sisestamisele vastab kõige korrasoleku puhul MySQL taas "Query OK", lisades sinna vahel ka mõjutatud ridade arvu ja kulunud aja - tähtis pigem suuremate andmestike korral. mysql> INSERT INTO lehed (pealkiri, sisu) VALUES ('Matemaatika', 'Homme tunnikontroll'); Query OK, 1 row affected (0.00 sec) SQLi selecti abil saab andmeid kergesti sobivas järjekorras ja kujul välja küsida. Kui lause lõppu lisatakse ORDER BY koos vastava tulba nimega, siis tulevad andmed välja selle tulba järgi tähestiku järjekorda panduna (kui vastav tulp oli tekstitulp). mysql> SELECT * FROM lehed ORDER BY sisu; +----+-------------+-------------------------+ | id | pealkiri | sisu | +----+-------------+-------------------------+ | 3 | Matemaatika | Homme tunnikontroll | | 1 | Ilmateade | Kuiv ilm | | 2 | Korvpall | Treening reedel kell 18 | +----+-------------+-------------------------+ 3 rows in set (0.00 sec) Saab küsida ka ainult ühe rea väärtusi: mysql> SELECT pealkiri, sisu FROM lehed WHERE id=3; +-------------+---------------------+ | pealkiri | sisu | +-------------+---------------------+ | Matemaatika | Homme tunnikontroll | +-------------+---------------------+ Kui leitakse, et rida pole enam vajalik, siis selle kustutamiseks sobib käsklus DELETE, kus soovitavalt id järgi määratakse ära, milline rida kustutada. mysql> DELETE FROM lehed WHERE id=3; Query OK, 1 row affected (0.00 sec) Uue SELECT-päringuga saab kontrollida, mis siis sinna tegelikult alles jäi. Kui nüüd juhtutaks INSERT-lausega taas andmeid lisama, siis sellele reale enam id väärtust 3 välja ei antaks - välistamaks näiteks olukorda, kus vanale teatele pandud kommentaarid satuksid uue külge. Primaarvõtmetulba id väärtuseks tuleks uue rea lisamisel vähemasti 4. mysql> SELECT * FROM lehed; +----+-----------+-------------------------+ | id | pealkiri | sisu | +----+-----------+-------------------------+ | 1 | Ilmateade | Kuiv ilm | | 2 | Korvpall | Treening reedel kell 18 | +----+-----------+-------------------------+ MySQList saab välja käsuga quit Ülesandeid * Tee näited läbi * Välju MySQList, sisene uuesti. * Lisa teadete tabelisse veel mõned read. * Väljasta teated sorteerituna pealkirja järgi * Loo tabel "veised" tulpadega id, veisenimi, mass ja vanus * Lisa mõned andmed * Väljasta andmed sordituna vanuse järgi * Väljasta ühe veise andmed id järgi. * Kustuta see veis. * Väljasta veised, kelle mass on 200-500kg (kahe tingimuse vahel AND). Andmetabeli sisu kuvamine PHP abil. MySQLi ja PHP ühendamiseks on aegade jooksul kasutatud mitmesuguseid vahendeid. Levinuimad on tõenäoliselt käsud mysql_connect, mysql_select_db ja mysql_query, millede abil on ka suurem osa kasutatavaid rakendusi kirjutatud. Selle komplekti puuduseks on aga sisendandmete suhteliselt vaba sattumine SQLi lausesse, mis teeb rakenduse kergemini haavatavaks. Aastaid on abiks kasutusel olnud eraldi loodud teek nimega PEAR (http://pear.php.net/). PHP 5. versiooniga aga tuli kaasa andmebaasipäringute poolest sarnaseid võimalusi pakkuv pakett MySQL Improved, mille abil ka siinse õppematerjali näited tehakse. Järgnev PHP-leht kuvab andmetabelis olnud teated ekraanile. MySQL Improved Extensioni (http://ee.php.net/mysqli) võimaluste kasutamiseks tuleb kõigepealt vastav objekt luua. $yhendus=new mysqli("localhost", "jaagup", "xxxxxx", "jaagup"); Edasi tehakse valmis käsklus. $kask=$yhendus->prepare("SELECT id, pealkiri, sisu FROM lehed"); Siis määratakse, millistesse muutujatesse satuvad tulpadest tulevad andmed ning käivitatakse käsklus andmebaasiserveris. Muutujatesse pannakse andmed samas järjekorras, kui need tulevad välja SELECT-lausest. $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); Kui andmed käes, siis võib neid ühe rea kaupa ette võtma hakata. Iga fetch() täidab bind_result- käsklusega määratud muutujad uue rea andmetega. Tsükkel while jätkab senikaua kuni päringu vastuseks veel ridu on, ehk kuni $kask->fetch tagastab tõese väärtuse kursori edasiliikumise õnnestumise kohta. Veebilehel näitamiseks pannakse pealkirjale ja sisule ümber käsklus htmlspecialchars - see asendab HTML-koodis tekstiosas lubamatud sümbolid (nt. < ja > ) vastavate asenduskombinatsioonidega ( < ja > nende märkide puhul). while($kask->fetch()){ echo "

".htmlspecialchars($pealkiri)."

"; echo "
".htmlspecialchars($sisu)."
"; } Lõpuks on viisakas ühendus kinni panna. Ilma vastava käsuta küll ühendus suletakse ka mingi aja pärast, kuid jääb siiski mõneks ajaks rippuma ning tiheda kasutusega serveris võib tekkida olukord, kus vabade andmebaasiühenduste limiit saab otsa ja mõnda aega pole võimalik baasipäringuid kasutada. Kui aga ühendus selgesõnaliselt kinni panna, siis on vastav kanal vaba ning selle võib avada uue päringu tarbeks. $yhendus->close(); Tabeli andmeid veebilehel näitav kood tervikuna: prepare("SELECT id, pealkiri, sisu FROM lehed"); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); ?> Teated lehel

Teadete loetelu

fetch()){ echo "

".htmlspecialchars($pealkiri)."

"; echo "
".htmlspecialchars($sisu)."
"; } ?> close(); ?> Käivitamise tulemusena valmis HTML: Teated lehel

Teadete loetelu

Ilmateade

Kuiv ilm

Korvpall

Treening reedel kell 18
Ning selle põhjal järgmise väljanägemisega veebileht: Ülesandeid * Hangi omale võimalus MySQL-andmebaasile käsklusi saata - olgu siis PHPMyAdmini, käsurea või mõne muu koha kaudu. * Loo/otsi veiste andmetabel (id, veisenimi, mass ja vanus), lisa mõned andmed * Näita andmed veebilehele * Vorminda andmed nummerdamata loeteluna ( ) * Vorminda andmed tabelina (
Veisenimi Mass Vanus
Maasu 400 5
Tipa 500 3
) * veiste puhul, kelle mass ületab 500 kg, määra tabeli lahtri klassiks ”rammus”. Stiilikäsklusega näita lahtrid klassist ”rammus” rasvases kirjas (font-weight: bold). * Koosta tabel koerte andmetega: id automaatselt suurenev primaarivõti, koeranimi kuni 30 sümboli pikkune tekst (VARCHAR) ning koera sünniaasta (INT). Lisa mõned andmed. * Küsi tabelist koerad kord nime, kord sünniaastate järgi järjestatuna välja- * Näita vaid koeri, kelle sünniaasta on suurem kui 2000. * Koosta veebileht, kus on näha kõikide andmetabelis olevate koerte nimed ja sünniaastad. * Kujunda leht kasutades võimalusel koerte pilte. Teadete valik Lühema sisuga teadete puhul sobib kõigi andmete korraga välja näitamine täiesti - vajalikud andmed on hea ülevaatlikult leida. Kui aga teated palju või nad pikemad, siis kipub kõige korraga nägemine tülikas olema. Esmaseks abiks sobib, kui algul paistavad välja vaid pealkirjad ning hiljem nendele vajutades saab ühe teate kaupa vaadata teate sisu teksti. Selleks tuleb lehele andmete vaatamiseks luua kaks suhteliselt eraldi osa: menüü teadete loetelu jaoks ning keskel olev sisuosa ühe valitud teate näitamiseks. Menüü kood on suhteliselt sarnane eelmise näite teadete loetelu omale. Lihtsalt loetelus näidatakse vaid teate pealkirja, sisu jäetakse näitamata. Pealkirjad muudetakse viideteks siiasamale failile nimega teadetevalik.php. Aadressiribale pannakse küsimärgi järel kaasa lähemalt vaadata soovitava teate id. Selle järgi on võimalik hiljem teate andmed küsida ning neid kasutada. Teine plokk on id järgi konkreetsete andmete küsimine baasist ning näitamine veebilehele. See võetakse ette vaid juhul, kui aadressiribale on lisatud parameeter nimega "id". SELECT-lausele tuleb selle väärtus bind_param-käsu kaudu sisse ajada. Jutumärkide vahel olev "i" näitab, et parameetrina etteantavad id-d loetakse integeri ehk täisarvuna. Muude sisendite puhul jõuab päringulausesse selle koha peale lihtsalt arv 0. Andmete kätte saamiseks määratakse bind_result-käskluse juures muutujate nimed, kuhu iga fetch- käsuga andmed sisestatakse. Endise while($kask->fetch) asemel on siin if($kask->fetch), sest mitut kirjet sama id põhjal nagunii küsida ei saa. Kui aga ühtegi ei anta, siis tõenäoliselt on keegi aadressiribale kirjutanud katsetamise huvides olematu id-numbri ning talle on viisakas teatada, et ta andmed on vigased. prepare("SELECT id, pealkiri, sisu FROM lehed WHERE id=?"); //Kysim2rgi asemele pannakse aadressiribalt tulnud id, //eeldatakse, et ta on tyybist integer (i). (double - d, string - s) $kask->bind_param("i", $_REQUEST["id"]); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); if($kask->fetch()){ echo "

".htmlspecialchars($pealkiri)."

"; echo htmlspecialchars($sisu); } else { echo "Vigased andmed."; } } else { echo "Tere tulemast avalehele! Vali menüüst sobiv teema."; } ?> Kui id-väärtust aadressiribal pole üldse märgitud, siis tõenäoliselt on tegemist lehe esmaavamisega, kus pole veel teate id-d määratud. Viisakuse poolest pannakse avatud ühendus lehe lõpul ka kinni. Kujundust enam eraldi failidesse paigutada pole mõtet, sest kogu andmete näitamise töö teebki ära üks ja seesama fail. Teated lehel

Teated

prepare("SELECT id, pealkiri, sisu FROM lehed WHERE id=?"); //Kysim2rgi asemele pannakse aadressiribalt tulnud id, //eeldatakse, et ta on tyybist integer (i). (double - d, string - s) $kask->bind_param("i", $_REQUEST["id"]); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); if($kask->fetch()){ echo "

".htmlspecialchars($pealkiri)."

"; echo htmlspecialchars($sisu); } else { echo "Vigased andmed."; } } else { echo "Tere tulemast avalehele! Vali menüüst sobiv teema."; } ?>
Lehe tegi Jaagup
close(); ?> Avalehel näidatav teatepealkirjade loetelu Valitud teate andmete kuvamine. Aadressiribal on näha valitud teate id. Ülesandeid * Mõelge/vaadake eelnenud näide läbi, vajadusel pange tööle. * Koosta/otsi andmetabel koerte/veiste andmete hoidmiseks * Loetelus on näha tabelisse sisestatud nimed * Koera nimele vajutamisel näidatakse muid andmeid selle looma kohta. Andmete lisamine ja kustutamine Baasist tulevaid andmeid on hea ja ilus vaadata, ent kuidagi peavad need andmed baasi saama. Kui andmestik kuigivõrd ei muutu, siis võib ju ka andmebaasi enese haldusliidese abil nad sinna kirja panna. Kui aga tahta, et tavakasutaja saaks mugavasti sättida, mis tal lehe peal kirjas, siis tema hea meelega PHP MyAdmini või otse SQL käsuviiba taha ei lähe. Lihtne arusaadav veebileht andmete sisestamiseks ja muutmiseks sobib palju paremini. Andmete lisamiseks tuleb kõigepealt toiminguga algust teha: kasutajale antakse pealkirjade menüü lõpus võimalus valida toiming "Lisa ...". Tehniliselt suunatakse kasutaja samale veebilehele, aga andes lehele kaasa parameetri lisamine=jah. Lisa ... Selle peale kuvatakse lehel välja sisestusvorm. Vormi kohustuslik parameeter on action, mis näitab lehe aadressi, kuhu andmed jõuavad. Kui kogu haldus toimub sama lehe juures, siis on mugavaks mooduseks kirjutada action'iks $_SERVER["PHP_SELF"] - siis pannakse sinna viide lehele enesele. Ning oma juurde saab ligi ka juhul, kui lehe nime vahetatakse. Hilisema toimingu eristamise huvides lisan varjatud väljana (hidden) ka teate uusleht=jah. if(isSet($_REQUEST["lisamine"])){ ?>

Uue teate lisamine

Pealkiri:
Teate sisu:
prepare("INSERT INTO lehed (pealkiri, sisu) VALUES (?, ?)"); $kask->bind_param("ss", $_REQUEST["pealkiri"], $_REQUEST["sisu"]); $kask->execute(); header("Location: $_SERVER[PHP_SELF]"); $yhendus->close(); exit(); } Andmete kustutamise juures tuleb kõigepealt kasutajale anda võimalus teate kustutamiseks. Sobib see näiteks teate vaatamise lehele, kus vastava teate andmed juba nagunii olemas on. Sealt loon viite samale lehele, andes aadressireal küsimärgi järele parameetri nimega "kustutusid", mille väärtuseks saab vastava teate id-number. if($kask->fetch()){ echo "

".htmlspecialchars($pealkiri)."

"; echo htmlspecialchars($sisu); echo "
kustuta"; } else { echo "Vigased andmed."; } Lehe uuel avamisel saab kontrollida, kas esineb parameeter kustutusid. Kui mitte, siis pole vaja kustutamisega tegelda. Kui aga leidub, siis tuleb sobiv DELETE-lause käivitada. Primaarvõtmeks olev id-number siin täisarvuna, sellest ka "i" bind_param käskluse esimese parameetrina. Kustutuse juures praegusel juhul korduva lehe avamise kontrolli ei ole, sest korduval sama id-ga teate kustutamisel ei juhtu midagi - vähemasti senikaua, kui pole eelnevat kontrolli tehtud, kas kustutatav asi üldse olemas on. Kui aga eeldan heauskset kasutajat, kes aadressireale käske ei kirjuta, vaid viisakasti viidete järgi rakendusega suhtleb, siis tal üksi oma lehestikku administreerides ei tohiks sellist üllatust juhtuda. if(isSet($_REQUEST["kustutusid"])){ $kask=$yhendus->prepare("DELETE FROM lehed WHERE id=?"); $kask->bind_param("i", $_REQUEST["kustutusid"]); $kask->execute(); } Edasi juba lisamis- ja kustutusvõimelise lehe kood tervikuna. prepare("INSERT INTO lehed (pealkiri, sisu) VALUES (?, ?)"); $kask->bind_param("ss", $_REQUEST["pealkiri"], $_REQUEST["sisu"]); $kask->execute(); header("Location: $_SERVER[PHP_SELF]"); $yhendus->close(); exit(); } if(isSet($_REQUEST["kustutusid"])){ $kask=$yhendus->prepare("DELETE FROM lehed WHERE id=?"); $kask->bind_param("i", $_REQUEST["kustutusid"]); $kask->execute(); } ?> Teated lehel

Teated

Lisa ...
prepare("SELECT id, pealkiri, sisu FROM lehed WHERE id=?"); $kask->bind_param("i", $_REQUEST["id"]); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); if($kask->fetch()){ echo "

".htmlspecialchars($pealkiri)."

"; echo htmlspecialchars($sisu); echo "
kustuta"; } else { echo "Vigased andmed."; } } if(isSet($_REQUEST["lisamine"])){ ?>

Uue teate lisamine

Pealkiri:
Teate sisu:
Lehe tegi Jaagup
close(); ?> Andmete lisamine veebilehel: Lisatud teate andmete vaatamine: Ülesandeid * Tee näide läbi * Koosta/otsi andmetabelipõhine veebileht koerte/veiste andmete vaatamiseks * Võimalda loomi lisada * Võimalda loomi kustutada Matka leht * Loo leht kasutajate lisamiseks matkale: eesnimi, perekonnanimi, telefon, elektronpost * Koosta leht matka tarbeks: marsruut, ajakava. Kujunda koos kasutajate lehega ühtseks lehestikuks. * Loo eraldi administraatorileht vigaste sisestuste kustutamiseks * Muuda ajakavalehte nõnda, et administraator saaks sinna sündmusi lisada ja sealt eemaldada. Võimalikke lisaülesandeid matkalehele: * Sisestuskontroll andmete korrektsuse kohta * Mitu kujundusfaili, mille vahetamisega saab üldkujundust (paigutus, pildid) märgatavalt muuta * Osalejate arvu teatamine avalehel * Teemade kaupa kataloogis olevate piltide näitamine galeriis samuti teemade kaupa Andmete muutmine veebilehel Lihtsaim andmete muutmine sageli koosnebki kustutamisest ja uuest lisamisest. Nii on mõnigi kord kergem teha, kui viisakamat muutmisvahendit luua. Pikkade ja keerukate andmete puhul pole aga kasutajad kuigivõrd rahul, kui väikese trükivea või täienduse pärast peaks terve rea jagu andmeid uuesti sisse panema. Samuti on kustutamiseta muutmine tähtis oludes, kus andmeid hakatakse juba omavahel siduma. Kui näiteks koeral on kindel omanik, ehk viide inimeste andmetabeli reale. Siis selle rea juures nt. telefoninumbri muutmisel jääb koera juurde ikka sama omanik. Kui aga telefoninumbri muutmiseks inimese rida ära kustutatakse ja uuesti luuakse, siis on juba keerukam hoolitseda, et koera juures andmebaasis kindel sama omanik oleks. Järgneva näite pealt näebki, kuidas PHP abil andmeid muuta nõnda, et ei peaks kõike maha kustutama ja uuesti sisestama, vaid saab paranduse paigutada vaid sobivasse kohta. Kõigepealt lisame kustutamise viite kõrvale viite ka muutmise kohta. Anname lehe uuel avamisel kaasa muudetava teate id, samuti parameetri "muutmine" väärtusega "jah". echo "
kustuta "; echo "muuda"; Nende põhjal saab siis järgmisel avamisel kontrollida, kas on seatud parameeter nimega "muutmine". if(isSet($_REQUEST["muutmine"])){ Kui jah, siis luuakse vorm ja pannakse sinna kaasa muutmisid - mille järgi siis muudatuste salvestamise juures teab, milllise teate juures muutus tuleb kirja panna. Väljadele antakse sisse olemasolevad väärtused, et neid saaks siis soovi järgi täiendada/parandada. Muutmisvormi loov koodilõik siit tervikuna silma ette. Tekstiväljale ja tekstialale saab vana sisu suhteliselt lihtsalt sisse panna. Rippenüüde puhul tuleb näiteks sobiv rida kavalasti ette kerida - aga sellest juba edaspidi. Ning eks peab jääma ka lõik tavalise teate näitamiseks - ilma muutmata. Ning viisakuse poolest ka kontroll selle kohta, et kui soovitakse olematut teadet - olgu siis aadressirea muutmise tõttu või selle poolest, et keegi vahepeal serverist teate ära kustutas - siis antakse ka sõnadega teada, et nende andmete põhjal teadet kätte ei saa. if($kask->fetch()){ if(isSet($_REQUEST["muutmine"])){ echo "

Teate muutmine

Pealkiri:
Teate sisu:
"; } else { echo "

".htmlspecialchars($pealkiri)."

"; echo htmlspecialchars($sisu); echo "
kustuta "; echo "muuda"; } } else { echo "Vigased andmed."; } Kui uued andmed sees, vajutatakse submit-nuppu ning andmed jõuavad taas lehele. Parameetri "muutmisid" olemasolu järgi teab, et nüüd tasub olemasoleva teate andmeid muutma hakata. Eks jällegi tuleb kokku panna SQL-lause. Kõik muudetavad väärtused saavad SET-osas omale veebilehelt tulnud andmete põhjal uue sisu ning lõpus WHERE osas määratakse, millise teate kohta see muutus käib. Siit kusjuures oht: kui kogemata unustatakse WHERE osa märkimata, siis kirjutatakse nende andmetega üle kõik tabelis leiduvad read ilma midagi eelnevalt küsimata ega kontrollimata. Parameetrite tüüpideks siin "ssi", sest pealkiri ja sisu on stringid, tabelirida määrav id aga integer. Käsk taas käima ning andmed muudetud. Siingi ei ole lehe ümbersuunamist tehtud, sest kui ka juhtutaks lehe värskendusnupule vajutama, siis kirjutataks uued andmed lihtsalt veel korra tabelisse ning midagi muud sellega ei kaasne. if(isSet($_REQUEST["muutmisid"])){ $kask=$yhendus->prepare("UPDATE lehed SET pealkiri=?, sisu=? WHERE id=?"); $kask->bind_param("ssi", $_REQUEST["pealkiri"], $_REQUEST["sisu"], $_REQUEST["muutmisid"]); $kask->execute(); } Edasi muutmisvõimelise lehe lähtekood tervikuna. prepare("INSERT INTO lehed (pealkiri, sisu) VALUES (?, ?)"); $kask->bind_param("ss", $_REQUEST["pealkiri"], $_REQUEST["sisu"]); $kask->execute(); header("Location: $_SERVER[PHP_SELF]"); $yhendus->close(); exit(); } if(isSet($_REQUEST["kustutusid"])){ $kask=$yhendus->prepare("DELETE FROM lehed WHERE id=?"); $kask->bind_param("i", $_REQUEST["kustutusid"]); $kask->execute(); } if(isSet($_REQUEST["muutmisid"])){ $kask=$yhendus->prepare("UPDATE lehed SET pealkiri=?, sisu=? WHERE id=?"); $kask->bind_param("ssi", $_REQUEST["pealkiri"], $_REQUEST["sisu"], $_REQUEST["muutmisid"]); $kask->execute(); } ?> Teated lehel

Teated

Lisa ...
prepare("SELECT id, pealkiri, sisu FROM lehed WHERE id=?"); $kask->bind_param("i", $_REQUEST["id"]); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); if($kask->fetch()){ if(isSet($_REQUEST["muutmine"])){ echo "

Teate muutmine

Pealkiri:
Teate sisu:
"; } else { echo "

".htmlspecialchars($pealkiri)."

"; echo htmlspecialchars($sisu); echo "
kustuta "; echo "muuda"; } } else { echo "Vigased andmed."; } } if(isSet($_REQUEST["lisamine"])){ ?>

Uue teate lisamine

Pealkiri:
Teate sisu:
Lehe tegi Jaagup
close(); ?> Piltidelt on näha, kuidas kõigepealt avatakse id järgi sobiv teade. Edasi muutmisviitele vajutades avatakse leht koos vormiga andmete muutmiseks: Siis saab parandused sisse viia Ning lõpuks tasub muudetud lehte imetleda. Ülesandeid * Tee näide läbi. * Anna muutmisel hoiatus juhul, kui sisestatud pealkirja pikkus ületab 50 sümbolit * Loo/otsi koerte/veiste andmeid näitav veebirakendus * Lisa rakendusele andmete muutmise võimalus. Väikefirma veebilehestik * Mõtle välja / lepi kaaslasega kokku firma, kellele veebileht teha (näiteks pagariäri, autoremonditöökoda) * Koosta kujundatud tutvustav leht. * Loo andmebaasitabel toodete hinnakirja tarbeks. Tutvustuslehelt pääseb hinnakirja vaatama. * Loo eraldi ligipääsuga andministraatorileht toodete hinnakirja haldamiseks (lisamine, muutmine, kustutamine). * Lisa veebilehestikule toodete/tööde pildigalerii, kuhu ilmuvad kõik kindlasse kataloogi kopeeritud pildid. Graafiline tekstiredaktor Aastaid oli veebikoostajate märgatavaks osaks tööst lehekülgede kaupa HTMLi kirjutada ja hoolitseda, et selle abil kirja pandud tekst rahvale viisakalt loetav oleks. Eks sellist kujundamist ole praegugi - kui tahtmist oma leht pikslipealt paika joonistada. Aga veebipõhised redaktorid aitavad küllaltki mugavalt tavakasutajatel omaloodud sisu kujundada ilma, et arvutiabilist pidevalt kõrval oleks. Graafilisi ehk WYSIWYG (What You See Is What You Get) tekstiredaktoreid veebilehel on tekkinud hulgem, tuleb vaid omale sobiv leida. Väiksematel piisab mõnekilobaidisest Javaskripti failist, keerukamatel võib allalaetav skript koos abipiltidega mitmesaja kilobaidini ulatuda. Samuti suudab mõni hakkama saada vaid üksikute brauserite ja versioonidega, teisel on paindlikkust rohkem. Kirjutise autor on juhtunud kasutama Javaskriptipõhiseid redaktoreid TinyMCE ja Kupu. Ning subjektiivselt parima mulje on jätnud CKEditor (endine FCKEditor). Seda kasutame ka siinses näites. Redaktor tuleb kõigepealt alla laadida ja lahti pakkida. Tasub vaadata, et kus kaustas asub fail ckeditor.js - see tuleb varsti meie lehe külge haakida. Siin puhul sattusid redaktori failid eraldi alamkausta ckeditor - seega laeme sisse faili aadressilt ckeditor/ckeditor.js. Uus versioon on nõnda targaks tehtud, et teksti ala graafiliseks redaktoriks muutmiseks on tarvis vaid talle külge panna atribuut class='ckeditor' Ning kui kõik andmed ilusti kätte saadakse, siis võibki rahulikult menüüst kujunduskäske valida ja teksti suurust muuta. Sama asi ka lisamise juures: tuleb lihtsalt vaadata, kus asub tekstiala, talle külge panna klass ckeditor ning jällegi on elu tunduvalt värvilisem. Kui millegipärast ei ole, siis tasub kõigepealt uurida, et kas viidatud kohast ikkagi javaskripti fail kergesti kätte saadakse. Selle aadressi võib kasvõi brauserireale sisse lüüa ja kontrollida, et mis sealt välja antakse. Samuti tasub kontrollida, et ega veebilehitsejal pole Javaskript kinni keeratud - turvapõhjustel seda mõnikord tehakse. if(isSet($_REQUEST["lisamine"])){ ?>

Uue teate lisamine

Pealkiri:
Teate sisu:
prepare("UPDATE lehed SET pealkiri=?, sisu=? WHERE id=?"); $kask->bind_param("ssi", $_REQUEST["pealkiri"], stripslashes($_REQUEST["sisu"]), $_REQUEST["muutmisid"]); $kask->execute(); } Lehtede tabeli loomiseks oli lause CREATE TABLE lehed( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, pealkiri VARCHAR(50), sisu TEXT ); Redaktorit kasutava lehe kood tervikuna. prepare("INSERT INTO lehed (pealkiri, sisu) VALUES (?, ?)"); $kask->bind_param("ss", $_REQUEST["pealkiri"], stripslashes($_REQUEST["sisu"])); $kask->execute(); header("Location: $_SERVER[PHP_SELF]"); $yhendus->close(); exit(); } if(isSet($_REQUEST["kustutusid"])){ $kask=$yhendus->prepare("DELETE FROM lehed WHERE id=?"); $kask->bind_param("i", $_REQUEST["kustutusid"]); $kask->execute(); } if(isSet($_REQUEST["muutmisid"])){ $kask=$yhendus->prepare("UPDATE lehed SET pealkiri=?, sisu=? WHERE id=?"); $kask->bind_param("ssi", $_REQUEST["pealkiri"], stripslashes($_REQUEST["sisu"]), $_REQUEST["muutmisid"]); $kask->execute(); } ?> Teated lehel

Teated

Lisa ...
prepare("SELECT id, pealkiri, sisu FROM lehed WHERE id=?"); $kask->bind_param("i", $_REQUEST["id"]); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); if($kask->fetch()){ if(isSet($_REQUEST["muutmine"])){ echo "

Teate muutmine

Pealkiri:
Teate sisu:
"; } else { echo "

".htmlspecialchars($pealkiri)."

"; echo $sisu; echo "
kustuta "; echo "muuda"; } } else { echo "Vigased andmed."; } } if(isSet($_REQUEST["lisamine"])){ ?>

Uue teate lisamine

Pealkiri:
Teate sisu:
Lehe tegi Jaagup
close(); ?> Ning näide CKEditori abil kujundatud teatest. Ülesandeid * Tutvu lehel http://ckeditor.com/ redaktori demoga * Loo või otsi rakendus koerte andmete sisestamiseks ja vaatamiseks * Võimalda koera kirjeldus kujundada graafilise redaktori abil. * Otsi võimalusel ka teisi Javaskripti-põhiseid redaktoreid ning katseta neid Veebilehestiku lõikude hoidmine andmebaasis Siiani tehtud näidetes on muudetav sisu olnud lehestiku struktuuri mõttes samas kohas - teateid on kord rohkem kord vähem, kuid nad saab ikka ühest loetelust kätte. Kui kellegi tarbeks veebilehestikku teha, siis on küllalt tavaline, et sisu soovitakse muuta mitmesugustes kohtades - täiesti erinevatel lehtedel ning ka lehe paigutuse suhtes mitmesugustes kohtades. Üheks võimaluseks sellist lehestikku veebi kaudu hallatavaks teha on hoida kõik muudetavad kohad teadetena andmebaasis ning lehe näitamisel siis vastavad sisud sealt välja võtta. Nõnda on lehe haldus suhteliselt sarnane siinsele teadete haldusele. Lehte sisu poolest näidatakse just sellisena nagu ta tehtud on ning tekstide muutmise võimalus ei sea kuigivõrd piiranguid lehestiku ülesehitusele. Lihtsalt muudetavaid kohti peab olema piiratud hulk- et nende hilisem otsimine teadete menüüst ei osutuks üle jõu käivaks. Viisaka plokkide nimetamise abil saab ka sellest murest üle. Funktsioonid eraldi failis Väiksema lehestiku puhul kannatab enamiku vajaminevast ühte faili kokku kirjutada. Mõnda aega on niimoodi hea ülevaatlik. Ning uue rakenduse loomiseks piisab lihtsalt vastava lehe kopeerimisest. Suurema rakenduse puhul aga kipuks nõnda ühes failis olevate koodiridade hulk keerukalt suureks minema. Ligikaudu tuhatkond rida on suurus, mida kannatab hea süsteemi korral veel ühes failis hallata. Üle selle kipub igatmoodi kirjuks minema. Kui aga funktsioonid teemade kaupa eraldi failidesse - põhjalikuma struktueerituse puhul ka klassidesse - paigutada, siis on lootust veel tükk aega rahus elada enne, kui kood päriselt üle pea kasvama kipub. Samuti on funktsioonide eraldamise eeliseks, et siis on kujundus võimalikult ühes failis ja programmeerimise pool teises. Nii ei teki liialt palju nii kujundajate kui ka arendajate poolt kirutud "spageti-koodi". Erinevalt mõnest muust keelest (ASP.NET, Zope lehemallid) ei ole PHPl kindlat ja üheselt tunnustatud koodi ja kujunduse eraldamise tava välja kujunenud, kuid kodeerimispraktikaid ja mallisüsteeme on loodud päris mitmesuguseid. Siin näites loodi eraldi fail "sisufunktsioonid.php", kuhu esimeses järjekorras pannakse funktsioon teate sisu küsimiseks vastavalt ploki id-numbrile. Lehtede tabelist küsitakse otsitud teate sisu ning tagastatakse funktsioonist. sisufunktsioonid.php prepare("SELECT sisu FROM lehed WHERE id=?"); $kask->bind_param("i", $id); $kask->bind_result($sisu); $kask->execute(); if($kask->fetch()){ return $sisu; } return "Andmed kadunud"; } ?> Avalehel - või ka mujal - teadete näitamiseks tuleb hoolitseda, et sisufunktsioonide fail oleks sisse loetud. Edasi saab teate andmed näidata andes funktsioonile ette vastava teatekoha identifikaatori. Kui kord teated valmis teha, siis edaspidi võib neile juba julgesti id järgi viidata. Kuni teadet vaid muudetakse, aga ei kustutata, senikauaks jääb id püsima. Nõnda siis piisabki hallatava sisuploki nägemiseks vaid kahest reast require_once("sisufunktsioonid.php"); echo kysiSisu(16); avaleht.php

Tore vahva asjalik autobaas

Meie uued uudised:
Menüüfail lehtede vahel navigeerimiseks menyy.php
Avaleht | Hinnakiri
Hinnakirjalehel kasutatakse samuti loodud funktsiooni sisu küsimiseks. Lihtsalt teate kood on erinev. hinnakirjaleht.php

Hinnakirja leht

Meie kehtiv hinnakiri:
Kui teated paigas, siis pole enam muud muret kui lehte vaatama asuda. Eks viisakas teemakohane kujundus ka külge - aga see on juba staatilise kujundamise asi millega mõnigi hakkama saab. Kui tegemist on peaasjalikult tutvustava/teatava lehega ning olulist infosüsteemi selle taga pole, siis teadete haldamise oskusest + nende lehel näitamise oskustest piisab peaaegu ükskõik kui ilusa ja keerulise lehestiku kokkupanekust. Autobaasi veebilehe redigeeritava avalehe demo. Ning lehe muutmine käib praegusel juhul täiesti vabalt sama teadete halduse lehestikku kasutades. Ülesandeid * Tee autobaasi lehestiku näide läbi * Kavanda ja koosta temaatiline kujundatud veebilehestik, kus mitmes vajalikus kohas saab sisu veebi kaudu muuta. Andmeid hoia eraldi selle rakenduse jaoks loodud tabelis, et ei tekiks segadusi seostest muude lehtedega. * Võimaluse korral võta kujunduse aluseks mõni juba valmis varem olev viimistletud kujundus (nt. lehelt http://www.freecsstemplates.org/ või midagi isetehtut). Lehtede muudetavad sisuosa plokid võta andmetabeli kirjetest eelnevalt näidatud moel.