Lahendusi ja täiendusi Päris algus * Käivita konspektis olnud näide kahe arvu liitmise kohta. * Muuda arve ja tehet, kontrolli tulemusi. Muutuja, valik ja kordus * Lisa tervitatavale inimesele perekonnanimi eraldi muutujasse, trüki ka selle väärtus. * Lisa tingimus üle saja-aastaste jaoks teatega "oled väga vana". * Lisa for-tsükli sisse iga Kuku järjekorranumber. 100){ echo "Oled hirmus vana!"; } for($i=0; $i<5; $i++){ echo "$i Kuku! "; } ?> PHP HTMLi sees Kahe sisestatud arvu korrutis Korrutamise puhul saab PHP ise aru, et pooled võiksid olla arvud. Seega annab soovitud tulemuse ka echo $_REQUEST["arv1"]*$_REQUEST["arv2"]; Kui tahta kindlasti andmetüübiks määrata täisarv, siis aitab funktsioon intval. Ehk siis echo intval($_REQUEST["arv1"])*intval($_REQUEST["arv2"]); Korrutamine

Korrutamine

x
Korrutustabel Pealkirjalahtriks tuleb veeru number, sest korrutustabeli puhul saab selle järgi otsida korrutatavale vastust. Sobivaks kujunduseks antakse siin lahtrile klassiks pealkiri, mille kohta siis üleval laadiplokis määratakse rasvane kujundus. echo "$veerg"; Tavalised lahtrid korrutustabelis saavad oma väärtuseks rea ja veeru numbri korrutise. Tehte puhul tuleb väljatrükitava teksti jutumärgid ära katkestada, avaldis välja arvutada ning punkt-operaatori abil kogu lugu taas üheks tervikuks väljatrükitavaks tekstiks kokku liita. echo "".($rida*$veerg).""; Korrutustabel

Korrutustabel

rida
veergu
"; for($rida=0; $rida<=$ridu; $rida++){ echo ""; if($rida==0){ //pealkirjarida echo ""; for($veerg=1; $veerg<=$veerge; $veerg++){ echo "$veerg"; } } else { echo "$rida"; for($veerg=1; $veerg<=$veerge; $veerg++){ echo "".($rida*$veerg).""; } } echo ""; } echo ""; } ?>
Lehe koostamine alamosadest Failitükke ühendav matkalehestik p2is.php Matka leht menyy.php

Menüü

kujundus.css body{ background-color: #ffeb90; } #menyy li { display: inline; width: 200px; } #menyy h2{ display: none; } jalus.php
Head matkamist!
osalejad.php

Osalejad

varustus.php

Varustus

marsruut.php

Marsruut

Andmefailid eraldi kataloogis Laulik p2is.php Laulik kujundus.css body{ background-color: #ffeb90; } #menyy{ float: left; padding-right: 30px; } #sisu{ width: 70%; float: left; } #loputeade{ clear: left; } menyy.php Andmete url-reale sobival kujul edasi andmiseks on loodud funktsioon urlencode - too asendab tühikud plussmärkidega ning muud erisümbolid kuueteistkümnendkoodiga, millele eelneb protsendimärk - nii nagu URLi andmete koostamise eeskiri ette näeb.

Menüü

lauluvaataja.php Sisseloetavas failinimes asendatakse kindlasti ära kaldkriips ning kaks punkti - vahendid, mille kaudu oleks muidu võimalik asuda veebiserveri kataloogide vahel liikuda ning ka neid andmeid välja õngitseda, mis isegi mitte veebi nähtavates kataloogides ei paikne. Käsu file_get_contents ees on @-märk seetõttu, et siis ei satu veateated olematu faili või muu probleemi tõttu tavakasutajaid häirima ega sissemurdjaid abistama.

 
Laulutekstid eraldi kataloogis nimega laulud. laulud/postipoiss.txt Postipoiss Palju aastaid mööda läinud sellest a'ast, kui veel olemas ei olnud meie maal ronge, autosid, jalgrattaid ega tehtud pikki matkaid, nagu tänapäeval kõikjal näha saad. Uhke postipoiss sõitis kord maanteel, külast külla, linnast linna viis ta tee. Kõikjal uudiseid tõi postipoiss kaugelt - nüüd vaid möödund ajast mälestus on see. On see, on see ... Külakõrts ja postijaam seal üheskoos. Soojas kambris oli tuju ikka hoos. Siis kui jalgu puhkas hobu, peeti külmarohust lugu ja siis sõit läks lahti jälle täies hoos. Kirja kallimalt ka postipoiss seal tõi. Vahel suudluse ta selle eest ka sai. Mitu hõberaha taskus selle vaeva ära tasus, mida teekond pikk tal kaasa tuua võis. Talvel lumi tuiskas, tormas maantee pääl. Juba kaugelt kostis aisakella hääl. Soojas kasukas seal sõitis mõni rikas linnakaupmees. Uinus magusasti, habe härmas ees. laulud/viljandi_paadimees.txt Viljandi paadimees Käe ulatab noor paadimees nii lahkelt neiule, kes aralt seisab tema ees, et sõita üle vee. Ah silmad, need silmad ei iial unune, need ilusad sinised silmad mul võitsid südame. Kui neiu paadis, algab sõit, täis õnne kõik maailm, siis neiu palgeil punab koit ja rõõmust särab silm. Ta kaela neiu langeb siis ja kingib suudluse. Silm särab rõõmupisarais, arm tungib südame. Hulk aastaid läind, kuid Viljandis järv ikka kohiseb. Hall paadimees veel ikkagi neid silmi igatseb. Pildialbum Menüüsse näidatakse kataloogis "pildid" olevatest failidest vaid need, mis on loetelus lubatud laiendiga. Lehele pannakse pildiviide etteantud failinimega. Erinevalt eelnevast laulikunäitest pole siin muret, et selle koodifaili järgi oleks võimalik veebiserverist andmeid õngitsema hakata. Kuna failinimi läheb ainult HTML-faili sisse, peab brauser hakkama ise andmeid küsima. Ning valest kohast juba veebiserver ise neid kätte ei anna. Pildid

Menüü

"; } ?>
Piltviidetega album Võrreldes eelnevaga näidatakse failinime kõrval ka selle pilti. Laiskuse ja koodi lihtsuse tõttu ei ole seda pilti eraldi väiksemaks tehtud, vaid lihtsalt HTML-käsuga määratakse menüüpiltidele väiksem suurus. Paljude piltide korral tekitab selline lähenemine jõudlusprobleeme. Et menüüd keritaks kõrval ja ta ei muudaks lehte liiga pikaks, selleks on menüü laadikäsklustesse lisatud overflow: scroll; overflow-x: hidden; Faili nimeks pildivaataja2.php Pildid

Menüü

"; } ?>
Ühe andmetabeliga seotud veebilehestik Veiste loetelu CREATE TABLE veised( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, veisenimi VARCHAR(50), mass INTEGER, vanus DOUBLE ); INSERT INTO veised (veisenimi, mass, vanus) VALUES ('Maasu', 400, 5); INSERT INTO veised (veisenimi, mass, vanus) VALUES ('Tipa', 500, 3.5); INSERT INTO veised (veisenimi, mass, vanus) VALUES ('Mammu', 300, 6); mysql> SELECT * FROM veised; +----+-----------+------+-------+ | id | veisenimi | mass | vanus | +----+-----------+------+-------+ | 1 | Maasu | 400 | 5 | | 2 | Tipa | 500 | 3.5 | | 3 | Mammu | 300 | 6 | +----+-----------+------+-------+ 3 rows in set (0.00 sec) prepare("SELECT id, veisenimi, mass, vanus FROM veised"); $kask->bind_result($id, $veisenimi, $mass, $vanus); $kask->execute(); ?> Veised lehel

Veiste loetelu

close(); ?> Veised tabelina Suurema massiga veistele lisatakse tabeli lahtrile klass "rammus", laadiga tehakse selle tekst rasvaseks. prepare("SELECT id, veisenimi, mass, vanus FROM veised"); $kask->bind_result($id, $veisenimi, $mass, $vanus); $kask->execute(); ?> Veised lehel

Veiste tabel

fetch()){ $veisenimi=htmlspecialchars($veisenimi); $lisand=""; if($mass>450){ $lisand=" class='rammus'"; } echo " "; } ?>
Veise nimi mass (kg) vanus (a)
$veisenimi $mass $vanus
close(); ?> Valitud veise vaatamine Lehe algul luuakse veisenimedest menüü. Nimele vajutades avatakse sama leht ning saadetakse aadressiribal parameetrina kaasa valitud veise id. Allpool kontrollitakse, et kas saabus parameeter nimega id. Kui jah, siis püütakse selle id järgi kätte saada ka veise ülejäänud andmed ning neid lehel näidata. Inglisekeelses kirjanduses kiputakse sellise lahenduse kohta ütlema master/detail vaade. Et pikk loetelu(menüü) on master ning valitud kirjet saab detailselt vaadata. Veised lehel

Veiste loetelu

prepare( "SELECT id, veisenimi, vanus, mass FROM veised 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, $veisenimi, $vanus, $mass); $kask->execute(); if($kask->fetch()){ echo "

".htmlspecialchars($veisenimi)."

"; echo "$vanus aastat, $mass kilogrammi"; } else { echo "Vigased andmed."; } } else { echo "Tere tulemast avalehele! Vali menüüst sobiv veis."; } ?>
Lehe tegi Jaagup
close(); ?> Kaks seotud tabelit Järgnevates näidetes hoitakse andmeid kahes tabelis. Ühes maakonnad maakonnanime ja -keskusega. Teises inimeste andmed. Kusjuures inimeste tabeli tulp maakonna_id näitab maakondade tabeli id peale. maakonnad(id, maakonnanimi, maakonnakeskus) inimesed (id, eesnimi, perekonnanimi, maakonna_id) Maakondade tabeli loomine: CREATE TABLE maakonnad( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, maakonnanimi VARCHAR(30), maakonnakeskus VARCHAR(30) ); Andmed sisse: INSERT INTO maakonnad (maakonnanimi, maakonnakeskus) VALUES ('Harjumaa', 'Tallinn'); INSERT INTO maakonnad (maakonnanimi, maakonnakeskus) VALUES ('Raplamaa', 'Rapla'); INSERT INTO maakonnad (maakonnanimi, maakonnakeskus) VALUES ('Saaremaa', 'Kuressaare'); INSERT INTO maakonnad (maakonnanimi, maakonnakeskus) VALUES ('Valgamaa', 'Valga'); Kontroll, et jõudsid kohale. mysql> SELECT * FROM maakonnad; +----+--------------+----------------+ | id | maakonnanimi | maakonnakeskus | +----+--------------+----------------+ | 1 | Harjumaa | Tallinn | | 2 | Raplamaa | Rapla | | 3 | Saaremaa | Kuressaare | | 4 | Valgamaa | Valga | +----+--------------+----------------+ Inimeste tabeli loomine CREATE TABLE inimesed( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, eesnimi VARCHAR(30), perekonnanimi VARCHAR(30), maakonna_id INT, FOREIGN KEY(maakonna_id) REFERENCES maakonnad(id) ); Andmed sisse INSERT INTO inimesed (eesnimi, perekonnanimi, maakonna_id) VALUES ('Juku', 'Tamm', 3); INSERT INTO inimesed (eesnimi, perekonnanimi, maakonna_id) VALUES ('Kati', 'Tamm', 3); INSERT INTO inimesed (eesnimi, perekonnanimi, maakonna_id) VALUES ('Mati', 'Kask', 2); Kahte tabelit ühendav päring. SELECT real tulpade nimed, mida näha tahetakse. FROM osas tabelite loetelu, kust andmeid saadakse. Ning WHERE-tingimusega määratakse, milliste tulpade väärtused peavad teisest tabelist rea võtmisel võrdsed olema. SELECT eesnimi, perekonnanimi, maakonnanimi FROM inimesed, maakonnad WHERE inimesed.maakonna_id=maakonnad.id +---------+---------------+--------------+ | eesnimi | perekonnanimi | maakonnanimi | +---------+---------------+--------------+ | Juku | Tamm | Saaremaa | | Kati | Tamm | Saaremaa | | Mati | Kask | Raplamaa | +---------+---------------+--------------+ M-iga algavad eesnimed mysql> SELECT * FROM inimesed WHERE eesnimi LIKE 'M%'; +----+---------+---------------+-------------+ | id | eesnimi | perekonnanimi | maakonna_id | +----+---------+---------------+-------------+ | 3 | Mati | Kask | 2 | +----+---------+---------------+-------------+ Kuressaares elavad inimesed. Lisaks tabeleid ühendavale tingimusele võib täiesti julgesti kasutada ka kõiksugu muid tingimusi. Vaid AND vahele üheaegse kehtivuse korral. Või kui lisandub valikuid ORi abil, siis enamasti on mõistlik sulgudega näidata, millised tingimused kokku kuuluvad - tabeleid siduv tingimus peab ikka eraldi jääma, muidu kipub andmete loetelu juures üllatusi tulema. SELECT eesnimi, perekonnanimi, maakonnanimi FROM inimesed, maakonnad WHERE inimesed.maakonna_id=maakonnad.id AND maakonnad.maakonnakeskus='Kuressaare'; +---------+---------------+--------------+ | eesnimi | perekonnanimi | maakonnanimi | +---------+---------------+--------------+ | Juku | Tamm | Saaremaa | | Kati | Tamm | Saaremaa | +---------+---------------+--------------+ Sorditud nimed Andmete kättesaamiseks sobiv funktsioon. Vaikimisi antakse ette tulbanimi ja suund, mille järgi sortida. Sellisel juhul võib funktsiooni rahumeeli ka ilma parameetriteta välja kutsuda. Funktsioonist veateate tagastamisel on mitu võimalust. Põhiosas olnud näide tagastas teksti "sobimatu tulp" - see aga ei pruugi kasutajale piisavalt selget tagasisidet anda. Alles siis, kui saabunud andmeid kasutama hakati, anti teada, et tekstist ei saa kirjeid samamoodi välja võtma hakata kui massiivist. Siin tagastatakse esimese kontrolli juures vigase tulbanime puhul lihtsalt tühi massiiv - ehk siis funktsiooni tagastustüüp jääb endisega võrreldes samaks. Sellisel juhul ei tekigi lehele mingit veateadet, lihtsalt näidatavad andmed jäävad tühjaks. Teises kontrollis olev funktsioon die trükib lihtsalt veateate ning lõpetab programmi töö - sellisel juhul pole karta et kasutaja võiks valesid andmeid kahtlustama hakata. abifunktsioonid.php prepare("SELECT inimesed.id, eesnimi, perekonnanimi, maakonnanimi, maakonnakeskus FROM inimesed, maakonnad WHERE inimesed.maakonna_id=maakonnad.id ORDER BY $sorttulp $sortsuund"); //echo $yhendus->error; $kask->bind_result($id, $eesnimi, $perekonnanimi, $maakonnanimi, $maakonnakeskus); $kask->execute(); $hoidla=array(); while($kask->fetch()){ $isik=new stdClass(); $isik->id=$id; $isik->eesnimi=htmlspecialchars($eesnimi); $isik->perekonnanimi=htmlspecialchars($perekonnanimi); $isik->maakonnanimi=htmlspecialchars($maakonnanimi); $isik->maakonnakeskus=htmlspecialchars($maakonnakeskus); array_push($hoidla, $isik); } return $hoidla; } //--------------- if( array_pop(explode("/", $_SERVER["PHP_SELF"]))=="abifunktsioonid.php"): ?>

Kõik andmed eesnimede järgi kahanevasse järjekorda sorditud: Array ( [0] => stdClass Object ( [id] => 3 [eesnimi] => Mati [perekonnanimi] => Kask [maakonnanimi] => Raplamaa [maakonnakeskus] => Rapla ) [1] => stdClass Object ( [id] => 2 [eesnimi] => Kati [perekonnanimi] => Tamm [maakonnanimi] => Saaremaa [maakonnakeskus] => Kuressaare ) [2] => stdClass Object ( [id] => 1 [eesnimi] => Juku [perekonnanimi] => Tamm [maakonnanimi] => Saaremaa [maakonnakeskus] => Kuressaare ) ) Andmete väljastamine veebilehel. Lehe päises otsustatakse valikute abil, milline väljakutsetest käiku läheb. Kui suund on olemas, järelikult on olemas ka tulp - sest siinse veebilehe viidete loomise süsteem lihtsalt töötab nii. Olemasolevate tulpade loetelu asub massiivis. Tükliga käiakse läbi kõik tulbad ning uuritakse, kas eelnevalt sorditi vastava tulba järgi (muutujas $_REQUEST["sorttulp"]) selle tulba nimi. Kui jah ning samas eelnevalt ei olnud lisandit, mis määraks kahanevas suunas sortimise, siis pannakse vastav lisand külge. Nõnda sorditakse tulba nime vajutamise peale kordamööda kasvavalt ja kahanevalt. Ilma korduse ja paljalt if-ide abil kirjutades oleks selline kontroll päris pikaks läinud. $tulbad=array("eesnimi", "perekonnanimi", "maakonnanimi", "maakonnakeskus"); foreach($tulbad as $tulp){ $lisand=""; if(isSet($_REQUEST["sorttulp"]) and $tulp==$_REQUEST["sorttulp"] and !isSet($_REQUEST["sortsuund"])){ $lisand="&sortsuund=tagasi"; } echo "$tulp"; } Loetelu fail tervikuna Inimeste leht $tulp"; } ?>
eesnimi ?> perekonnanimi ?> maakonnanimi ?> maakonnakeskus ?>
Otsing LIKE ? abil Niisama vabalt LIKE-avaldise sisse küsimärgiga parameetrit panna MySQL Improved ei kannata. Küll aga saab metamärkidega teksti enne PHP abil valmis ehitada ning siis SQL-lausesse küsimärkide asemele sättida nagu järgnevas lõigus. Ka siin pole muret, et tekstisse sattunud ülakomad ja muud erisümbolid segadust tekitada võiksid. Algses konspektis pruugitud addslashes- käsu asemel soovitatakse kasutada mysql_real_escape_string. Viimane aga nõuab serveril vastava mooduli küljesolekut ning ei pruugi igal pool töötada. Selles mõttes siinne küsimärkidega asendus kõige kindlam. $kask=$yhendus->prepare("SELECT inimesed.id, eesnimi, perekonnanimi, maakonnanimi, maakonnakeskus FROM inimesed, maakonnad WHERE inimesed.maakonna_id=maakonnad.id AND (eesnimi LIKE ? OR perekonnanimi LIKE ?) ORDER BY $sorttulp $sortsuund"); echo $yhendus->error; $otsiparam='%'.$otsisona.'%'; $kask->bind_param("ss", $otsiparam, $otsiparam); $kask->bind_result($id, $eesnimi, $perekonnanimi, $maakonnanimi, $maakonnakeskus); abifunktsioonid.php tervikuna prepare("SELECT inimesed.id, eesnimi, perekonnanimi, maakonnanimi, maakonnakeskus FROM inimesed, maakonnad WHERE inimesed.maakonna_id=maakonnad.id AND (eesnimi LIKE ? OR perekonnanimi LIKE ?) ORDER BY $sorttulp $sortsuund"); echo $yhendus->error; $otsiparam='%'.$otsisona.'%'; $kask->bind_param("ss", $otsiparam, $otsiparam); $kask->bind_result($id, $eesnimi, $perekonnanimi, $maakonnanimi, $maakonnakeskus); $kask->execute(); $hoidla=array(); while($kask->fetch()){ $isik=new stdClass(); $isik->id=$id; $isik->eesnimi=htmlspecialchars($eesnimi); $isik->perekonnanimi=htmlspecialchars($perekonnanimi); $isik->maakonnanimi=htmlspecialchars($maakonnanimi); $isik->maakonnakeskus=htmlspecialchars($maakonnakeskus); array_push($hoidla, $isik); } return $hoidla; } //--------------- if( array_pop(explode("/", $_SERVER["PHP_SELF"]))=="abifunktsioonid.php"): ?>

Otsitavate andmete näitamine Kui edasiantavaid muutujaid juba rohkem ning nende lisandumise järjekord teadmata, siis on kindlam kõikidele muutujatele panna vaikeväärtused ning need aadressirealt saabuvate andmetega üle kirjutada. Inimeste leht
$tulp"; } ?>
eesnimi ?> perekonnanimi ?> maakonnanimi ?> maakonnakeskus ?>
Igasuguse tabeli näitamine Eelnevas koodis olid tulpade nimed selgelt sisse kirjutatud. Sellisel juhul aga peab nende lisandumisel/muutumisel ka koodi sisse mitmesse kohta parandusi tegema. Järgnev näide võimaldab igasuguse SQL-lausega küsitud andmed tabelina veebilehel välja näidata. Kuna SQL- lause väljund on paratamatult tabel, siis on see võimalik. Käsklused $yhendus->real_query($lause); $vastus=$yhendus->store_result(); kahe peale annavad mälus oleva andmetabeli. Käsu fetch_row abil saab sealt ükshaaval ridu välja võtta ning foreach-tsükli abil kõik väljad tabeli lahtritena ekraanile kuvada. while($rida=$vastus->fetch_row()){ echo ""; foreach($rida as $tulbasisu){ echo "".htmlspecialchars($tulbasisu).""; } echo ""; } Fail tervikuna: tabelinaitamine.php real_query($lause); $vastus=$yhendus->store_result(); ?> Inimeste leht fetch_row()){ echo ""; foreach($rida as $tulbasisu){ echo ""; } echo ""; } ?>
".htmlspecialchars($tulbasisu)."
mysqli tulpade uuring Soovides päringusse ka parameetreid panna, on viisakam prepare-käsuga käsklus ette valmistada ja parameetrid küsimärkide kaudu sisestada. Näite lühiduse huvides pole siin parameetrit lisatud, aga see loodetavasti eelmistest näidetest tuttav. Kõige keerukam osa näitest tõenäoliselt on väljastusparameetrite tarbeks muutujate ette valmistamine. Üldjuhul bind_param saab omale parameetriks nõnda palju muutujaid, kui palju tulpi SELECT-lauses väljastatakse. Siin me aga ei tea kindlat tulpade arvu, sest me tabel peab hakkama saama igasuguste päringutega. Selleks siis koostatakse muutujate massiiv nõnda, et massiivi iga element saab oma andmed aadressilt, kuhu bind_param-käsu järgi välja õpetatud fetch need paneb. Et tegeldakse mäluaadressiga, seda näitab &-märk omistuse juures. Massiivi indeksiks saab tulba nimi. Massiivi lõppu omistamiseks sobib käskluse $muutujad[]=uusväärtus. while($tulbaandmed=$metaandmed->fetch_field()){ $muutujad[] = &$rida[$tulbaandmed->name]; } bind_result käsule massiivitäie muutujate ette andmine käib järgnevalt: call_user_func_array(array($kask, 'bind_result'), $muutujad); Ning kood tervikuna. prepare($lause); $kask->execute(); ?> Inimeste leht result_metadata(); echo ""; while($tulbaandmed=$metaandmed->fetch_field()){ echo ""; $muutujad[] = &$rida[$tulbaandmed->name]; } echo ""; call_user_func_array(array($kask, 'bind_result'), $muutujad); while($kask->fetch()){ echo ""; foreach($rida as $tulbasisu){ echo ""; } echo ""; } ?>
$tulbaandmed->name
".htmlspecialchars($tulbasisu)."
Inimeste haldus Seotud tabelitesse andmete lisamisel on programmeerija jaoks hea selge loogika: kõigepealt tuleb andmed panna sinna tabelisse kuhu viidatakse. Ning alles seejärel on põhjust andmeid panna tabelisse kust viidatakse. Ehk siis kõigepealt sisestatakse maakonnad ning alles pärast seda inimesed - juhul kui inimesel peab kirjas olema tema paiknemise maakonna id. Samuti tuli lisada enne kaubagrupid ning alles siis sai lisada kaupu, valides rippmenüüst lisatavale kaubale sobiv grupp. Kasutajaliidese seisukohalt ei ei pruugi selline lähenemine aga kasutajatele loogiline ega mugav tunduda. Kategooriate või märksõnade puhul tõenäoliselt tahaks inimene valida neid olemasolevate hulgast või lisada uusi. Ning uute lisamiseks ta parema meelega ei lähe neid teisele lehele või mujale kaugele lisama - ta tahab oma toimetused ühe koha peal valmis saada. Javaskriptiga saab muidugi ka mitmesuguseid abivahendeid luua, aga siin näites teeme PHP vahenditega kasutajale ehk selle koha pealt võimalikult mugava rakenduse. Kõigepealt muudame või lisame eelneva inimeste halduse näitega võrreldes mõned funktsioonid, et neid saaks hiljem kasutajaliidese loomise juures pruukida. Kasutaja jaoks inimese ja maakonna üheaegsel lisamisel tuleb tehniliselt ikkagi uus maakond kõigepealt tabellisse panna ning küsida selle maakonna id. Seejärel saab lisada inimese andmed tema tabelisse ning määrata talle maakonna_id väärtuseks vastloodud maakonna id. Õnneks saab loodud tabelirea id-väärtuse kätte MySQL Improved Statementi (ehk muutuja $kask) väljalt insert_id. Selle siis nüüd funktsioonid lõpus tagastamegi. function lisaMaakond($maakonnanimi, $maakonnakeskus){ global $yhendus; $kask=$yhendus->prepare( "INSERT INTO maakonnad (maakonnanimi, maakonnakeskus) VALUES (?, ?)"); $kask->bind_param("ss", $maakonnanimi, $maakonnakeskus); $kask->execute(); return $kask->insert_id; } Hoolitsemaks, et sama nimega maakond ei satuks tabelisse mitu korda, on hea panna maakonnanime tulbale unikaalsuse piirang. ALTER TABLE maakonnad ADD UNIQUE(maakonnanimi); Inimese ja maakonna andmete üheaegseks lisamiseks tuleb uus funktsioon, mis saab enesele mõlema tabeli jaoks vajalikud parameetrid. Kõigepaelt uuritakse, kas etteantud maakonnanimega maakond on maakondade tabelis juba olemas. Kui jah, siis lihtsalt küsitakse selle maakonna id ning lisatakse inimese juurde vastava maakonna id. Kui aga pakutud nimega maakonda pole, siis see luuakse eelpooltoodud käsuga, saadakse tagasi loodud maakonna id ning antakse see kaasa inimese andmete lisamisel. function lisaInimeneKoosMaakonnaga($eesnimi, $perekonnanimi, $maakonnanimi, $maakonnakeskus){ global $yhendus; $maakonna_id=kysiYksikV22rtusBaasist( "SELECT id FROM maakonnad WHERE maakonnanimi=?", $maakonnanimi); if(!$maakonna_id){ $maakonna_id=lisaMaakond($maakonnanimi, $maakonnakeskus); } lisaInimene($eesnimi, $perekonnanimi, $maakonna_id); } Olemasoleva maakonna nime küsimiseks ning ka muude võimalike hilisemate toimingute tarbeks lõime abifunktsiooni üksiku väärtuse küsimiseks. Selle abil saab mõneski kohas hea jupi koodi kokku hoida. Ning võimalus päringule ka üks parameeter anda, nagu vahel ette tuleb. Kui päringus kõik olemas ja parameetrit pole vaja, siis seda ei lisata. Maakonnanime järgi id otsimisel on aga igati kasulik, et veebist tulev maakonnanimi õnnestub SQL-lauses küsimärgi kohale paigutada, mitte ei pea muretsema erisümbolite võimaliku mõju üle SQL lauses. function kysiYksikV22rtusBaasist($sqllause, $parameeter=false){ global $yhendus; $kask=$yhendus->prepare($sqllause); echo $yhendus->error; if($parameeter){ $kask->bind_param("s", $parameeter); } $kask->bind_result($vastus); $kask->execute(); if(!$kask->fetch()){return false;} return $vastus; } Rippmenüü loomise funktsioonile tuli juurde võimalus elemendi märgendi sisse täiendav lisand kirjutada - näiteks stiilikäskluse või Javaskripti tarbeks nagu siin näites hiljem kasutatakse. Et tegemist valikulise viimase parameetrina, siis võib teda rahumeeli ainult vajaduse korral kasutada ning muul juhul kõrvale jätta. function looRippMenyy($sqllause, $valikunimi, $valitudid="-1", $ylalisand="") Edasi fail tervikuna: abifunktsioonid.php prepare("SELECT inimesed.id, eesnimi, perekonnanimi, maakonnanimi, maakonnakeskus FROM inimesed, maakonnad WHERE inimesed.maakonna_id=maakonnad.id AND (eesnimi LIKE ? OR perekonnanimi LIKE ?) ORDER BY $sorttulp $sortsuund"); echo $yhendus->error; $otsiparam='%'.$otsisona.'%'; $kask->bind_param("ss", $otsiparam, $otsiparam); $kask->bind_result($id, $eesnimi, $perekonnanimi, $maakonnanimi, $maakonnakeskus); $kask->execute(); $hoidla=array(); while($kask->fetch()){ $isik=new stdClass(); $isik->id=$id; $isik->eesnimi=htmlspecialchars($eesnimi); $isik->perekonnanimi=htmlspecialchars($perekonnanimi); $isik->maakonnanimi=htmlspecialchars($maakonnanimi); $isik->maakonnakeskus=htmlspecialchars($maakonnakeskus); array_push($hoidla, $isik); } return $hoidla; } function kysiInimeseAndmed($id){ global $yhendus; $kask=$yhendus->prepare("SELECT eesnimi, perekonnanimi, maakonna_id FROM inimesed WHERE id=?"); $kask->bind_param("i", $id); $kask->bind_result($eesnimi, $perekonnanimi, $maakonna_id); $kask->execute(); echo $yhendus->error; if(!$kask->fetch()){return false;} $isik=new stdClass(); $isik->id=$id; $isik->eesnimi=htmlspecialchars($eesnimi); $isik->perekonnanimi=htmlspecialchars($perekonnanimi); $isik->maakonna_id=$maakonna_id; return $isik; } function muudaInimeseAndmed($id, $eesnimi, $perekonnanimi, $maakonna_id){ global $yhendus; $kask=$yhendus->prepare("UPDATE inimesed SET eesnimi=?, perekonnanimi=?, maakonna_id=? WHERE id=?"); $kask->bind_param("ssii", $eesnimi, $perekonnanimi, $maakonna_id, $id); $kask->execute(); } function looRippMenyy($sqllause, $valikunimi, $valitudid="-1", $ylalisand=""){ global $yhendus; $kask=$yhendus->prepare($sqllause); $kask->bind_result($id, $sisu); $kask->execute(); $tulemus=""; return $tulemus; } function lisaMaakond($maakonnanimi, $maakonnakeskus){ global $yhendus; $kask=$yhendus->prepare( "INSERT INTO maakonnad (maakonnanimi, maakonnakeskus) VALUES (?, ?)"); $kask->bind_param("ss", $maakonnanimi, $maakonnakeskus); $kask->execute(); return $kask->insert_id; // ALTER TABLE maakonnad ADD UNIQUE(maakonnanimi); } function lisaInimene($eesnimi, $perekonnanimi, $maakonna_id){ global $yhendus; $kask=$yhendus->prepare( "INSERT INTO inimesed (eesnimi, perekonnanimi, maakonna_id) VALUES (?, ?, ?)"); $kask->bind_param("ssi", $eesnimi, $perekonnanimi, $maakonna_id); $kask->execute(); } function lisaInimeneKoosMaakonnaga($eesnimi, $perekonnanimi, $maakonnanimi, $maakonnakeskus){ global $yhendus; $maakonna_id=kysiYksikV22rtusBaasist( "SELECT id FROM maakonnad WHERE maakonnanimi=?", $maakonnanimi); if(!$maakonna_id){ $maakonna_id=lisaMaakond($maakonnanimi, $maakonnakeskus); } lisaInimene($eesnimi, $perekonnanimi, $maakonna_id); } function kustutaInimene($id){ global $yhendus; $kask=$yhendus->prepare("DELETE FROM inimesed WHERE id=?"); $kask->bind_param("i", $id); $kask->execute(); } function kysiYksikV22rtusBaasist($sqllause, $parameeter=false){ global $yhendus; $kask=$yhendus->prepare($sqllause); echo $yhendus->error; if($parameeter){ $kask->bind_param("s", $parameeter); } $kask->bind_result($vastus); $kask->execute(); if(!$kask->fetch()){return false;} return $vastus; } //--------------- if( array_pop(explode("/", $_SERVER["PHP_SELF"]))=="abifunktsioonid.php"): ?>

Pärast vajaminevate funktsioonide loomist saab asuda rahus kasutajaliidest looma. Eraldi tähelepanu väärib rippmenüü loomine. Rippmenüü loomise funktsioon soovib saada SQL-päringu, mille tulemusena küsitakse baasist kahetulbaline tabel. Kui aga olemasolevat maakonda pole loetelus, siis peaks olema mugav moodus uue lisamiseks. Et funktsioonile on praegusel kujul võimalik andmeid ette anda vaid SQL-kujul, siis siitkaudu uue rea lisamegi. Olematu maakonna koodiga 0 teate "Lisa uus". Sellise rea annab SELECT '0', 'Lisa uus' mysql> SELECT '0', 'Lisa uus'; +---+----------+ | 0 | Lisa uus | +---+----------+ | 0 | Lisa uus | +---+----------+ Käsuga UNION ALL saab olemasoleva päringu vastuste lõppu lisada teise päringu vastused. mysql> SELECT id, maakonnanimi FROM maakonnad -> UNION ALL (SELECT '0', 'Lisa uus'); +----+------------------+ | id | maakonnanimi | +----+------------------+ | 1 | Harjumaa | | 2 | Raplamaa | | 3 | Saaremaa | | 4 | Valgamaa | | 8 | Hiiumaa | | 9 | Viljandi maakond | | 10 | Tartu maakond | | 11 | Põlva maakond | | 12 | Ida-Virumaa | | 0 | Lisa uus | +----+------------------+ Nõnda saabki kavala lause abil SQLi vastuste tulemusena loodud valikusse andmed sisse anda. Maakonna sisestamise lahtrid maakonnanimi ja maakonnakeskus said koos nende sisu selgitavate siltidega paigutatud omaette tabelisse id-ga maakonnasisestus. Neid sisestusvälju on põhjust näha vaid juhul, kui kasutaja on valinud uue maakonna lisamise. Tabeli peitmist ja näitamist korraldab Javaskripti funktsioon kontrolliValik, millele antakse kaasa väljakutsuva rippmenüü muutuja (this).
Maakond:

Ülal skriptiosas oleva funktsiooni abil näidatakse tabelit vaid juhul, kui ees on rippmenüüst viimane valik. Omadus selectedIndex näitab valitud rea järjekorranumbrit, rippmenyy.options.length aga valikuridade arvu. Kuna lugemine algab nullist, siis viimane rida on valitud parajasti siis, kui selectedIndex on elementide arvust ühe võrra väiksem. Ning koodifail tervikuna. inimhaldus.php Inimeste haldamise leht

Andmete lisamine

Eesnimi:
Perekonnanimi:
Maakond:

Andmete muutmine
Eesnimi:
Perekonnanimi
Maakond
". looRippmenyy("SELECT id, maakonnanimi FROM maakonnad", "maakonna_id", $isik->maakonna_id) ."
"; } } ?>
$tulp"; } ?> "; } ?>
haldus
k m $isik->eesnimi $isik->perekonnanimi $isik->maakonnanimi $isik->maakonnakeskus
Ja mõned vaated valminud rakendusele. Ja Artur ongi lisatud koos maakonnaga. Uudiste leht Võõra kujunduse kohandamine Järgnevas näites võetakse aluseks eelnevalt valmis ja vabalt saadaval olev kujundus ning kohandatakse sinna külge rakendus, kus saab uudiseid lisada ja iga uudist eraldi kommenteerida. Selline ühendamine sarnaneb täiesti "tavaliste" rakenduste loomisega, kus kujundaja ülesandeks ongi ilus leht valmis teha ning programmeerija tööks siis sinna sisse õigetele kohtadele vajalikud andmed paigutada. Mõnigase otsimise peale leidsime, et kujundusaluseks sobiks lepatriinuga tumedal taustal kujundus. http://www.freecsstemplates.org/preview/bugslife Veebilehelt alla tõmmatud zip-failist tekkis lahti pakkimisel hulk faile ja katalooge. Lähemal uurimisel selgus siiski, et põhipildi ette kuvamiseks on tarvis üht HTML-faili, tema juurde kuuluvat CSS-i ning üht taustapilti. Muud failid osutusid abiõpetusteks või lihtsalt vanadest versioonidest sisse ununenud piltideks. Nii et kui asuda oma rakendust mõne muu süsteemiga ühendama, on sellega kasulik eelnevalt tutvuda ning vaadata, mida tegelikult vaja läheb. Nagu pildi pealt näha, on lehe ülaosas pilt koos sinna juurde kuuluva pealkirjatekstiga. Vasakul pool menüü mitmesuguste viidetega ning paremal pool teatekast(id) sisu jaoks. Koodist selgub, et vasaku ploki moodustab kiht id-ga colOne ning parempoolse kiht id-ga colTwo. Ning teine plokk saadakse paremale hõljuma käsuga #colTwo { float: right; width: 390px; } Nad mõlemad paiknevad kihis id-ga content, millel on kindel laius määratud. Üheks võimaluseks võõrast koodi "oma kontrolli" alla saada on asuda plokke oma keelde või oma süsteemi järgi ümber nimetama - siis näha, milliste asjadega on eraldi tegeletud. Siin näiteks nimetasime kõigepealt kujundusfaili kujundus.css-iks. Bugs Life by Free Css Templates

Welcome to Bugs life!

Bugs Life is a free template from Free CSS Templates released under a Creative Commons Attribution 2.5 License. The header photo is from PDPhoto.org. You're free to use it for both commercial or personal use. I only ask that you link back to my site in some way. Enjoy :)

Suspendisse Potenti

Sed vestibulum blandit nisl. Quisque elementum convallis purus. Quisque pellentesque semper massa:

kujundus.css /* Design by Free CSS Templates http://www.freecsstemplates.org Released for free under a Creative Commons Attribution 2.5 License */ body { margin: 0; padding: 0; background: #000000; font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 11px; color: #707070; } h1, h2, h3 { text-transform: lowercase; font-family: Georgia, "Times New Roman", Times, serif; font-weight: normal; font-style: italic; color: #FF941D; } h2 { font-size: 24px; } h3 { font-size: 18px; } p, ol, ul, blockquote { line-height: 22px; } a { border-bottom: 1px dotted #707070; text-decoration: none; color: #BFBFBF; } a:hover { border: none; } strong { color: #8D8C8C; } /* Posts */ .post { margin-bottom: 9px; padding: 20px 40px 20px 60px; background: #131313; border-top: 1px solid #1F1F1F; border-right: 1px solid #1F1F1F; border-bottom: 1px solid #1F1F1F; border-left: 1px solid #1F1F1F; } .post h2, .post h3 { margin-left: -40px; } /* Header */ #header { width: 600px; height: 280px; margin: 0 auto; background: url(lepatriinu.jpg); } #header h1 { margin: 0; padding: 180px 0 0 20px; font-size: 36px; } #header h2 { margin: 0; padding: 0 0 0 92px; font-size: 16px; } #header a { border: none; letter-spacing: -1px; color: #FF941D; } /* Content */ #content { width: 580px; margin: 0 auto; padding: 10px; } #colOne { float: left; width: 180px; } #colOne ul { margin-left: 0; padding-left: 0; list-style: none; } #colTwo { float: right; width: 390px; } /* Footer */ #footer { clear: both; width: 580px; margin: 0 auto; padding-top: 20px; } #footer p { margin: 0; text-align: center; font-size: 9px; } #footer * { color: #333333; } Koodi puhastus Järgmisena tasub võõrast koodist võimalikult palju lõike eemaldada - jätta alles vaid need, mis on omapoolse rakenduse toimimise juures vajalikud. Pole isegi liigset eemaldamist karta - sest kui ka midagi sai liialt välja võetud, siis saab ju alati algsest originaalist sobiva lõigu uuesti sisse võtta. Kuna lihtsa uudistelehestiku puhul piisab vasakule vaid uudiseviidetest, siis saigi sealt colOne seest kõik muu peale paari viite välja võetud. Pealkirja sisse omale sobivad teemad. Ning on näha, et stiililehelt määratud text-transform:lowercase teeb kõik sisestatu väiketähtedeks. Teise veergu jääb alles ka vaid üks kast ühe näituudisealusega. Jalus las esiotsa püsib - viisakas on näidata, kust kujundus võetud. Loodusuudised

kotkasilm ja tiivatuul

Vuh-vuh-vuh... lendab merikotkas vuhinal madallennul e mu pea, korraks riivavad ta võimsad hoosuled rannamändide latvu, siis saab ta tiibadele tuule alla ja kaob järvele...
Edasi

Putukad eeltalvel

Kui nüüd nädalavahetusel läheb aina soojemaks, tasub metsas kõndides kindlasti tähele panna ka putukaid
Edasi

Nõnda siis juba tunduvalt lühema ning omapoolsema koodiga leht, mille võib jätta programmipoolset andmete lisamist ootama. Andmebaasiliides Veebirakenduse juures tasub järgmisena luua andmetabelid. Kui soovime, et igat uudist saaks eraldi kommenteerida, siis kulub kaks tabelit: üks uudiste tarbeks, teine kommentaaride jaoks. Ning nõnda, et iga kommentaari juures on kirjas kommenteeritava uudise id. Alustuseks aga uudised valmis ja katsetusse. CREATE TABLE uudised( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, pealkiri VARCHAR(100), sisu TEXT ); INSERT INTO uudised(pealkiri, sisu) VALUES('Esimene uudis', 'Esimese uudise tutvustav lause. Pikem jutt edasi'); Uudistega seotud toimingud koondame omaette klassi - see aitab rakendust omaette seisvate tükkidena püsida. Klassi sisse käsklus uudiste tutvustuste küsimiseks. Seal antakse välja iga uudise id, pealkiri, sisu ning samuti vaid esimene lause, mida hea avalehele tutvustuseks panna. Praegusel juhul eeldatakse, et lause lõpetab punkt. Ning käsklus explode tükeldab lause punkti koha pealt massiivielementideks ning neist antakse välja omakorda esimene ehk m[0]. abifunktsioonid.php ab=$yhendus; } function kysiTutvustused($algus=0, $kogus=3){ $kask=$this->ab->prepare("SELECT id, pealkiri, sisu FROM uudised"); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); $hoidla=array(); while($kask->fetch()){ $uudis=new stdClass(); $uudis->id=$id; $uudis->pealkiri=htmlspecialchars($pealkiri); $uudis->sisu=htmlspecialchars($sisu); $m=explode(".",$sisu); $uudis->algus=htmlspecialchars($m[0]); array_push($hoidla, $uudis); } return $hoidla; } } $uudised=new Uudised($yhendus); ?> Lehel pole enam muud muret, kui et menüüsse tsükliga kirjutada uudiste pealkirjad. Igalt pealkirjalt tuleb viide samale PHP-failile, mille avamisel antakse kaasa uudise id. Samasugune loetelu sai esiotsa pandud ka sisuploki kastidesse. Ainult selle vahega, et seal kuvatakse lisaks pealkirjale veel uudise esimene lause. Hiljem võib lisada piirangu, et mitme (viimase) uudise andmeid kus näidata. kysiTutvustused(); ?> Loodusuudised

$rida->pealkiri

$rida->algus;
Loe edasi ...

"; } ?>
Edasi loome kommentaaride tabeli. Tulp "korras" näitab, et kas seda sobib uudise juures kuvada. CREATE TABLE kommentaarid( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, kommenteerija VARCHAR(50), kommentaarisisu VARCHAR(50), uudise_id INT, korras INT DEFAULT 1 ); Abifunktsioonidesse tuleb juurde kommentaaride klass. Kusjuures siin tehti nõnda, et kommentaaride klassi eksemplaril on alati enese küljes olemas uudise id, millega vastavad kommentaarid seotud - nii on pärast vähem andmete liigutamist. Kommentaaride lisamisel saadakse uudise id siis juba objekti muutujast. Kommentaaride küsimisel pole aga vaja midagi ette anda - kui juba vahendusobjekt olemas, siis saab sealt seest ka kommentaarid kätte. Väljaspoole klassi sai loodud funktsioon tootleSisend. Muidu kipub avatava veebifaili päises tekkivaid programmeerimistoiminguid hulgem tulema ning kujunduse ja koodi erisusest jääb vähe järele. Kui aga toimetused eraldi failis olevasse funktsiooni tuua, siis jääb näidatav fail puhtamaks. Kui on teada kuvatava uudise id, siis luuakse selle tarbeks ka kommentaariobjekt. Ning kui parajasti lisati kommentaar, siis saab loodud objekt ka selle salvestamisega hakkama. Administraatori jaoks on uudisteklassis juures käsklus uudiste lisamise jaoks. abifunktsioonid.php ab=$yhendus; } function kysiTutvustused($algus=0, $kogus=3){ $kask=$this->ab->prepare("SELECT id, pealkiri, sisu FROM uudised ORDER BY id DESC"); $kask->bind_result($id, $pealkiri, $sisu); $kask->execute(); $hoidla=array(); while($kask->fetch()){ $uudis=new stdClass(); $uudis->id=$id; $uudis->pealkiri=htmlspecialchars($pealkiri); $uudis->sisu=htmlspecialchars($sisu); $m=explode(".",$sisu); $uudis->algus=htmlspecialchars($m[0]); array_push($hoidla, $uudis); } return $hoidla; } function kysiUudis($id){ $kask=$this->ab->prepare("SELECT pealkiri, sisu FROM uudised WHERE id=?"); $kask->bind_param("i", $id); $kask->bind_result($pealkiri, $sisu); $kask->execute(); if(!$kask->fetch()){ die("Vigane uudise ID"); } $uudis=new stdClass(); $uudis->id=$id; $uudis->pealkiri=htmlspecialchars($pealkiri); $uudis->sisu=htmlspecialchars($sisu); return $uudis; } function lisaUudis($pealkiri, $sisu){ $kask=$this->ab->prepare("INSERT INTO uudised (pealkiri, sisu) VALUES (?, ?)"); $kask->bind_param("ss", $pealkiri, $sisu); $kask->execute(); } } class Kommentaarid{ private $ab, $uudise_id; function __construct($yhendus, $uid){ global $uudised; $this->ab=$yhendus; $this->uudise_id=$uid; $uudised->kysiUudis($uid); } function lisaKommentaar($kommenteerija, $kommentaarisisu){ $kask=$this->ab->prepare("INSERT INTO kommentaarid (kommenteerija, kommentaarisisu, uudise_id) VALUES (?, ?, ?)"); $kask->bind_param("ssi", $kommenteerija, $kommentaarisisu, $this->uudise_id); $kask->execute(); } function kysiKommentaarid(){ $kask=$this->ab->prepare("SELECT id, kommenteerija, kommentaarisisu FROM kommentaarid WHERE uudise_id=? AND korras=1 ORDER BY id DESC"); $kask->bind_param("i", $this->uudise_id); $kask->bind_result($id, $kommenteerija, $kommentaarisisu); $kask->execute(); $hoidla=array(); while($kask->fetch()){ $kommentaar=new stdClass(); $kommentaar->id=$id; $kommentaar->kommenteerija=htmlspecialchars($kommenteerija); $kommentaar->kommentaarisisu=htmlspecialchars($kommentaarisisu); array_push($hoidla, $kommentaar); } return $hoidla; } } function tootleSisend(){ global $kommentaariobj; global $yhendus; if(isSet($_REQUEST["uid"])){ $kommentaariobj=new Kommentaarid($yhendus, $_REQUEST["uid"]); } else { return; } if(isSet($_REQUEST["kommentaarisisestus"])){ $kommentaariobj->lisaKommentaar($_REQUEST["kommenteerija"], $_REQUEST["kommentaarisisu"]); header("Location: $_SERVER[PHP_SELF]?uid=$_REQUEST[uid]"); exit(); } } $uudised=new Uudised($yhendus); ?> Uudiste lehel näidatakse avamisel vasakmenüüs uudiste pealkirju ning keskel lühitutvustusi. Ühe uudise valimisel avaneb üksikute tutvustuste asemel lehe peal see uudis ning alla lisandub kommenteerimisvorm ja olemasolevad kommentaarid. uudised.php kysiTutvustused(); ?> Loodusuudised

$rida->pealkiri

$rida->algus;
Loe edasi ...

"; } } else { $rida=$uudised->kysiUudis($_REQUEST["uid"]); echo "

$rida->pealkiri

$rida->sisu

Lisa kommentaar

Kommenteerija nimi:

Kommentaari sisu:

"; $kommentaarimassiiv=$kommentaariobj->kysiKommentaarid(); foreach($kommentaarimassiiv as $kommentaar){ echo "

$kommentaar->kommenteerija

$kommentaar->kommentaarisisu

"; } } ?>
Administraatorileht Administraatorilehel on vajalik koht uudiste lisamiseks, samuti kommentaaride eemaldamiseks. Kuna abifunktsioonide fail on kõigile kasutada, siis turvakaalutlustel ei pandud vastavate funktsioonide väljakutseid URLi pealt saabuvate andmete põhjal sinna, vaid tehakse need toimingud administraatorilehe päises. Kui nüüd hiljem administraatorileht kaitsta parooli ja sessioonimuutuja abil, või näiteks paigutada eraldi kausta, kus ligipääsuõigused .htaccess-faili abil piiratud, siis tavakasutaja enam uudiseid lisada või kommentaare sobimatuks muuta ei saa. Nagu põhjalikumatele andmelehtedele kohane, siin sobimatuid kommentaare ei kustutata, vaid lihtsalt määratakse eraldi tulbas, et nad ei ole "korras". Eelnenud abifunktsioonide faili sai juba lisatud, et näidataks vaid korras kommentaare - niimoodi jääbki veebileht viisakaks, samas on baasist aga võimalik jälitada, et mida siis vahepeal on lehele kirjutada suvatsetud. admin.php lisaUudis($_REQUEST["uudisepealkiri"], $_REQUEST["uudisesisu"]); header("Location: $_SERVER[PHP_SELF]"); exit(); } if(isSet($_REQUEST["pahakommentaar"])){ $kask=$yhendus->prepare("UPDATE kommentaarid SET korras=0 WHERE id=?"); $kask->bind_param("i", $_REQUEST["pahakommentaar"]); $kask->execute(); } $loetelu=$uudised->kysiTutvustused(); ?> Loodusuudised
Uudise pealkiri:

Uudise sisu:

"; } if(!isSet($_REQUEST["uid"])){ foreach($loetelu as $rida){ echo "

$rida->pealkiri

$rida->algus
Loe edasi ...

"; } } else { $rida=$uudised->kysiUudis($_REQUEST["uid"]); echo "

$rida->pealkiri

$rida->sisu

Lisa kommentaar

Kommenteerija nimi:

Kommentaari sisu:

"; $kommentaarimassiiv=$kommentaariobj->kysiKommentaarid(); foreach($kommentaarimassiiv as $kommentaar){ echo "

$kommentaar->kommenteerija

$kommentaar->kommentaarisisu

eemalda

"; } } ?>
Smarty Lihtne tervitus Lihtne tervitus Smarty abil. Esimese käsuna loetakse sisse Smarty põhiklassi fail (tasub vaadata, millises kataloogis ta asub). Edasi Smarty objekt valmis ning võibki mallilehte kuvada. tervitus1.php display("tervitus1.tpl"); ?> Mallilehed asuvad vaikimisi kaustas templates. Tasub jälgida, et sinna kõrvale oleks tehtud ka kaust templates_c ning antud sellele kõik õigused - siis võimalik Smartyl lehti käivituskõlbulikuks kompileerida. Aga esimene malllinäide näeb välja nagu täiesti tavaline HTML-leht. templates/tervitus1.tpl Tervitusleht

Tervitamise leht

Vaatamiseks tuleb avada ikka algne PHP-fail. Andmete edastamine Mallide üks põhivõlu on selles, et siin saab PHP muutujad ette valmistada, mallifailidele ette anda ning viimane lihtsalt kuvab neid sobiva koha peal - ilma, et peaks ise kusagilt väärtusi küsima minema. Siin näites anname mallile ette teate väärtuse. tervitus2.php assign("teade", "Tervitame koduseid gripihaigeid."); $smarty->display("tervitus2.tpl"); ?> Looksulgude vahel $teade kuvab sobivasse kohta teate ekraanile. templates/tervitus2.tpl Tervitusleht

Tervitamise leht

{$teade}
Mitme failiga komplekt Mallide abil võib lehe jagada julgesti alamosadeks ning siis neid vajadust mööda välja kutsuda. Siin näites on eraldi mallifailiks päis, eraldi ühe jooksja andmete kuvamine ning lõpuks eraldi jalus. templates/jooksjad_p2is.tpl Tervitusleht

Jooksjate leht

templates/jooksjad_jooksja.tpl
Tervitame meie tublit jooksjat kel nimeks {$eesnimi}, kes saavutas {$kohanr}. koha!
templates/jooksjad_jalus.tpl PHP-failis näidatakse kõigepealt päis. Siis igale jooksja andmed kujundatuna jooksja malli järele. Ning lõpuks jalus. Nõnda on kujundajal täiesti vabad käed jooksja andmete ilusaks muutmiseks - ainult muutujate nimed peavad paika jääma. jooksjad.php display("jooksjad_p2is.tpl"); $koht=0; foreach($eesnimed as $eesnimi){ $koht++; $smarty->assign("eesnimi", $eesnimi); $smarty->assign("kohanr", $koht); $smarty->display("jooksjad_jooksja.tpl"); } $smarty->display("jooksjad_jalus.tpl"); ?> Kahe arvu korrutamine Lihtne sisestusega veebilehe näide, kus kogu kujundus on mallifailis, arvutus aga PHP-s. templates/korrutamine.tpl Korrutusleht

Korrutamise leht

x {$vastusteade}
korrutamine.php assign("vastusteade", $vastusteade); $smarty->display("korrutamine.tpl"); ?> Mitu mitmele seos Bussipeatused ja liinid Näide järgnevate tabelite sidumise põhjal nagu ülal antud ülesandes kirjas. * Koosta peatuste tabel (id, peatusenimi). Lisa mõned peatused * Koosta liinide tabel (liini_nr, liininimetus). Lisa mõned liinid * Koosta peatumisaegade tabel (id, liini_nr, peatuse_id, aeg_algpeatusest). Lisa mõned peatumised * Koosta reiside tabel(id, liini_nr, algusaeg, suund) (1-edasi, 2-tagasi). * Koosta leht ühe bussiliini peatumisandmete näitamiseks. Andmed sorditakse peatusesse jõudmise aja järgi. SQL-laused Eks andmeid saab talletada mitmeti. Siin on eraldi "põhitabeliteks" peatused ja liinid. Ning peatumisaegade tabel seob need tabelid omavahel kokku, märkides seose juurde, kui palju igasse peatusesse jõudmiseks aega algpeatusest kulub. CREATE TABLE peatused( id INT NOT NULL auto_increment PRIMARY KEY, peatusenimi VARCHAR(50) ); INSERT INTO peatused(peatusenimi) VALUES ('Viljandi'); INSERT INTO peatused(peatusenimi) VALUES ('Karksi'); INSERT INTO peatused(peatusenimi) VALUES ('Tartu'); INSERT INTO peatused(peatusenimi) VALUES ('Valga'); INSERT INTO peatused(peatusenimi) VALUES ('Puhja'); INSERT INTO peatused(peatusenimi) VALUES ('Elva'); Nagu näha, pole liinide juures automaatselt suurenevat primaarvõtit. Kuna liini number ise peab olema unikaalne, siis võib selle rahumeeli ka ise ja otse INSERT-lausest sisse kirjutada. CREATE TABLE liinid( liini_nr INT NOT NULL PRIMARY KEY, liini_nimetus VARCHAR(50) ); INSERT INTO liinid VALUES (10, 'Viljandi-Valga kiir'); INSERT INTO liinid VALUES (11, 'Viljandi-Elva-Tartu'); INSERT INTO liinid VALUES (12, 'Karksi-Tartu'); Peatuste ja liinide sidumiseks on vaja teada peatuste id-sid. SELECT * FROM peatused; +----+-------------+ | id | peatusenimi | +----+-------------+ | 1 | Viljandi | | 2 | Karksi | | 3 | Tartu | | 4 | Valga | | 5 | Puhja | | 6 | Elva | +----+-------------+ CREATE TABLE peatumisajad( id INT NOT NULL auto_increment PRIMARY KEY, liini_nr INT, peatuse_id INT, aeg_algpeatusest TIME ); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(10, 1, '00:00'); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(10, 2, '00:30'); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(10, 4, '01:30'); Ühe liini andmed olemas. Edasi peab veel koodide järgi vaatama, millist marsruuti liin sõidab. mysql> SELECT * FROM peatumisajad; +----+----------+------------+------------------+ | id | liini_nr | peatuse_id | aeg_algpeatusest | +----+----------+------------+------------------+ | 1 | 10 | 1 | 00:00:00 | | 2 | 10 | 2 | 00:30:00 | | 3 | 10 | 4 | 01:30:00 | +----+----------+------------+------------------+ INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(11, 1, '00:00'); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(11, 5, '00:45'); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(11, 6, '01:00'); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(11, 3, '01:35'); Kui peatumisaegade tabelis on juba rohkemate liinide andmed, siis tuleb ühe liini andmete kätte saamiseks määrata, millise liini peatusi tahetakse. mysql> SELECT * FROM peatumisajad WHERE liini_nr=11; +----+----------+------------+------------------+ | id | liini_nr | peatuse_id | aeg_algpeatusest | +----+----------+------------+------------------+ | 4 | 11 | 1 | 00:00:00 | | 5 | 11 | 5 | 00:45:00 | | 6 | 11 | 6 | 01:00:00 | | 7 | 11 | 3 | 01:35:00 | +----+----------+------------+------------------+ INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(12, 2, '00:00'); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(12, 6, '01:15'); INSERT INTO peatumisajad(liini_nr, peatuse_id, aeg_algpeatusest) VALUES(12, 3, '01:55'); Peatumisaegade tabelis on kirjas vaid ajad algpeatusest. Tahtes teada tegelikke peatusest väljumise aegu, tuleb algsetele aegadele liita juurde algpeatusest väljumise aeg. Õnneks on MySQLil olemas käsklus ADDTIME. SELECT ADDTIME('13:10', aeg_algpeatusest) FROM peatumisajad WHERE liini_nr=11 ORDER BY aeg_algpeatusest; +------------------------------------+ | ADDTIME('13:10', aeg_algpeatusest) | +------------------------------------+ | 13:10:00 | | 13:55:00 | | 14:10:00 | | 14:45:00 | +------------------------------------+ Väljundist on rohkem kasu, kui väljumiskellaaja kõrvale pannakse ka peatuse nimi, mille kohta see käib. Selleks ühendatakse peatumisaegade tabeli kõrvale peatuste tabel ning näidatakse sealt välja vaid rida, mille id vastab peatuseaegade tabelist kuvatava rea peatuse id-ga. Kellaaja tulbale antakse AS käsklusega endise valemi asemel viisakas nimi. Kuna andmebaasis vaikimisi ei ole ajad järjestatud, siis on kasulik tulemus aegade järgi sortida. Muidu võivad küll peatumisajad õiged olla, aga liini peatusi ei pruugita näidata õiges järjekorras. SELECT peatusenimi, ADDTIME('13:10', aeg_algpeatusest) as kellaaeg FROM peatumisajad, peatused WHERE peatumisajad.peatuse_id=peatused.id AND liini_nr=11 ORDER BY aeg_algpeatusest; +-------------+----------+ | peatusenimi | kellaaeg | +-------------+----------+ | Viljandi | 13:10:00 | | Puhja | 13:55:00 | | Elva | 14:10:00 | | Tartu | 14:45:00 | +-------------+----------+ 13.10 oli eelmise näite juures lihtsalt katseks võetud algusaeg. Tegelikkuses on ju sageli samal liinil päevas mitu reisi. Ning bussid sõidavad samal liinil mõlemas suunas. Nii tulebki reiside tabelisse kirja liini nr, väljumisaeg ning suund. Kokkuleppeliselt tähistasime siin algpeatusest lõpppeatuse poole liikuva suuna ühega ning tagasisuuna kahega. CREATE TABLE reisid( id INT NOT NULL auto_increment PRIMARY KEY, liini_nr INT, algusaeg TIME, suund INT DEFAULT 1 ); Mõned andmed sisse ka. INSERT INTO reisid (liini_nr, algusaeg) VALUES (11, '13:10'); INSERT INTO reisid (liini_nr, algusaeg) VALUES (11, '16:10'); INSERT INTO reisid (liini_nr, algusaeg, suund) VALUES (11, '16:10', 2); INSERT INTO reisid (liini_nr, algusaeg) VALUES (10, '9:15'); Pärisuunas reisi aegadega suaab suhteliselt lihtsalt hakkama - eelmises päringus tuleb 13:10 asendada lihtsalt konkreetse reisi algusajaga ning võibki tulemustega rahul olla. Tagasireisiga on aga rohkem tegemist. Üldjuhul võiks liinil peatuste vahel mõlemas suunas liikumine sama palju aega võtta. On kindlasti erandeid, aga sel juhul on on tõenäoliselt üheks lahenduseks teha vähemasti andmebaasi tasemel kaks erinevat liini - üks kummagi suuna jaoks. Ning sõita neil liinidel vaid edasisuunas. Kui aga tegemist tavalise sirge ja sileda ühetaolise tee liiniga, siis tasub kõigepealt leida liini läbimise aeg, ehk siis lõpppeatusesse jõudmise aeg. Ning sealt hakata ükshaaval ülejäänud aegu lahutama. Lõpppeatusest iseenese aja lahutamine annab tulemuseks nulli - aga seda meil ju vaja ongi. Tagasisuunas sõites tulebki buss ju reisi väljumise ajal lõpppeatusest välja. Lõpppeatuse ja temale eelneva peatuse aja vahe näitab, kui palju kulub tolle viimase või siis tagasisuunas esimese peatusevahe läbimiseks. Jällegi on ka seda meil vaja: nii palju tuleb siis tagantotsast väljumise ajale juurde liita, et eelneva peatuse aeg saada. Kõik algpeatusest kulunud ajad 11nda liini kohta leiab päringuga: SELECT aeg_algpeatusest FROM peatumisajad WHERE liini_nr=11; Suurim neist on lõpppeatuseni jõudmise aeg: SELECT MAX(aeg_algpeatusest) FROM peatumisajad WHERE liini_nr=11; Edasi lahutan sellest ajast iga peatuse kohta tabelis oleva aja. Lahutamiseks ikka käsklus ADDTIME, ainult, et tulbal aeg_algpeatusest on miinusmärk ees. SELECT ADDTIME( (SELECT MAX(aeg_algpeatusest) FROM peatumisajad WHERE liini_nr=11), -aeg_algpeatusest ) as aeg FROM peatumisajad where liini_nr=11 order by aeg; +----------+ | aeg | +----------+ | 00:00:00 | | 00:35:00 | | 00:50:00 | | 01:35:00 | +----------+ Tahtes peatuste nimed ka juurde saada, siis tuleb sellele päringule juurde lisada veel peatuste tabel ning sealt id järgi soovitud nimi välja võtta. SELECT peatusenimi, ADDTIME( (SELECT MAX(aeg_algpeatusest) FROM peatumisajad WHERE liini_nr=11), -aeg_algpeatusest ) as aeg FROM peatumisajad, peatused WHERE peatumisajad.peatuse_id=peatused.id AND liini_nr=11 ORDER BY aeg; Veebiliides Edasi paras aeg nende päringute abil veebileht tööle panna. Laiskuse ja lihtsuse tõttu pole siia eraldi faile tekitatud, vaid andmebaasipäringud ja HTMLi kood on kõik ühe lehe peal koos. Alustuseks liininumbrite loetelu: prepare("SELECT liini_nr, liini_nimetus FROM liinid"); $kask->bind_result($liini_nr, $liini_nimetus); $kask->execute(); while($kask->fetch()){ echo "
  • $liini_nr $liini_nimetus
  • \n"; } ?> Edasi iga liini väljumisajad mõlemas suunas. IF-lausega juba SQL-lauses pannakse tulpa "suundtekst" sisse sõidusuunda näitav sõna. $kask=$yhendus->prepare("SELECT id, algusaeg, if(suund=1, 'edasi', 'tagasi') as suundtekst FROM reisid WHERE liini_nr=?"); Konkreetse reisi peatusaegade näitamine on sedakorda jaotatud kahe päringu vahel - üks läinuks muidu liialt keerukaks. Kõigepealt saab reisi_id järgi kätte liinu nubri, algusaja ja suuna. $kask=$yhendus->prepare( "SELECT liini_nr, algusaeg, suund FROM reisid WHERE id=?"); $kask->bind_param("i", $_REQUEST["reisi_id"]); $kask->bind_result($liini_nr, $algusaeg, $suund); $kask->execute(); $kask->fetch(); $kask->close(); Vastavalt suunale koostatakse edasine SQL-lause. Pärisuuna puhul piisab peatusest väljumise aja arvutamiseks reisi alguskellaaja ja vastava peatuseni kuluva aja liitmisest. Tagasisuuna puhul aga tehakse läbi eelnevalt näidatud keerukam arvutus. Ning et liini numbri parameetrit ei peaks SQL-lausesse mitu korda sisestama, selleks on suurimat aega leidvas alampäringus olev lauseses tabel peatumisajad nimetatud p1-ks, et saaks sealset liininumbrit võrrelda allpool oleva sama tabeli liininumbriga. if($suund==1){ $ajalause="ADDTIME(?, aeg_algpeatusest)"; } else { $suurimaeg="SELECT MAX(aeg_algpeatusest) FROM peatumisajad as p1 WHERE p1.liini_nr=peatumisajad.liini_nr"; $ajalause="ADDTIME(?, ADDTIME(($suurimaeg), -aeg_algpeatusest))"; } Aega arvutav lauseosa lisatakse lõpuks sobivale kohale põhilause sisse. $lause="SELECT peatusenimi, $ajalause as aeg FROM peatumisajad, peatused WHERE peatumisajad.peatuse_id=peatused.id AND peatumisajad.liini_nr=? ORDER BY aeg"; $kask=$yhendus->prepare($lause); $kask->bind_param("si", $algusaeg, $liini_nr); $kask->bind_result($peatusenimi, $aeg); $kask->execute(); while($kask->fetch()){ echo "$peatusenimi$aeg"; } Ning PHP-fail tervikuna. vaataja.php Liinide leht

    Liinide loetelu

    Reisid liinil

    Reis koodiga

    prepare( "SELECT liini_nr, algusaeg, suund FROM reisid WHERE id=?"); $kask->bind_param("i", $_REQUEST["reisi_id"]); $kask->bind_result($liini_nr, $algusaeg, $suund); $kask->execute(); $kask->fetch(); $kask->close(); if($suund==1){ $ajalause="ADDTIME(?, aeg_algpeatusest)"; } else { $suurimaeg="SELECT MAX(aeg_algpeatusest) FROM peatumisajad as p1 WHERE p1.liini_nr=peatumisajad.liini_nr"; $ajalause="ADDTIME(?, ADDTIME(($suurimaeg), -aeg_algpeatusest))"; } $lause="SELECT peatusenimi, $ajalause as aeg FROM peatumisajad, peatused WHERE peatumisajad.peatuse_id=peatused.id AND peatumisajad.liini_nr=? ORDER BY aeg"; $kask=$yhendus->prepare($lause); $kask->bind_param("si", $algusaeg, $liini_nr); $kask->bind_result($peatusenimi, $aeg); $kask->execute(); while($kask->fetch()){ echo ""; } ?>
    $peatusenimi$aeg
    Viide samale tabelile Viidete abil seotud võivad olla ka sama tüüpi andmed. Kataloogipuus on ülemkataloog samuti kataloog nagu alamkataloog. Ning kui tegemist inimeste tabeliga, siis iga inimese isa ja ema on samuti inimesed ning nende andmeid saab inimeste tabelis hoida. Lõputult pole sugupuus andmeid ning kusagilt maalt peavad esivanemate viited tühjaks jääma. Aga päris hulga sugupõlvi kannatab nõnda üles tähendada küll. Selle põhjal ka mõned ülesanded ja lahendused. * Looge tabel isikud(id, eesnimi, synniaasta, isa_id, ema_id) CREATE TABLE isikud( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, eesnimi VARCHAR(50) NOT NULL, synniaasta INT NOT NULL, isa_id INT, ema_id INT ); * Lisage andmed. Kui vanema isikut pole tabelis, siis selle koha peal tühiväärtus NULL Andmestiku aluseks võtame perekonna, kus on lapsed Juku ja Kati, isa Martin, ema Anne. Ning Martini vanemad on Juhan ja Marta. Anne vanemaid pole tabelisse kantud. Samuti mitte Juhani ja Marta vanemaid. Lapsed: Juku 2005 Kati 2003 Vanemad: Martin 1970 Anne 1974 Vanavanemad Juhan 1935 Marta 1938 Kui muud vaikimise väärtust pole määratud, siis tulebki määramata tulpade (isa_id ja ema_id) väärtuseks NULL. Vanimad tegelased tuleb kõigepealt sisse kanda, sest nende IDsid on vaja järgnevate isikute vanemate määramisel. INSERT INTO isikud(eesnimi, synniaasta) VALUES('Juhan', 1935); INSERT INTO isikud(eesnimi, synniaasta) VALUES('Marta', 1938); Pärast andmete sisestamist saab küsida need välja koos automaatselt lisatud ID-dega. mysql> SELECT * FROM isikud; +----+---------+------------+--------+--------+ | id | eesnimi | synniaasta | isa_id | ema_id | +----+---------+------------+--------+--------+ | 1 | Juhan | 1935 | NULL | NULL | | 2 | Marta | 1938 | NULL | NULL | +----+---------+------------+--------+--------+ INSERT INTO isikud(eesnimi, synniaasta, isa_id, ema_id) VALUES ('Martin', 1970, 1, 2); INSERT INTO isikud(eesnimi, synniaasta) VALUES ('Anne', 1974); mysql> SELECT * FROM isikud; +----+---------+------------+--------+--------+ | id | eesnimi | synniaasta | isa_id | ema_id | +----+---------+------------+--------+--------+ | 1 | Juhan | 1935 | NULL | NULL | | 2 | Marta | 1938 | NULL | NULL | | 3 | Martin | 1970 | 1 | 2 | | 4 | Anne | 1974 | NULL | NULL | +----+---------+------------+--------+--------+ INSERT INTO isikud(eesnimi, synniaasta, isa_id, ema_id) VALUES ('Juku', 2005, 3, 4); INSERT INTO isikud(eesnimi, synniaasta, isa_id, ema_id) VALUES ('Kati', 2003, 3, 4); mysql> SELECT * FROM isikud; +----+---------+------------+--------+--------+ | id | eesnimi | synniaasta | isa_id | ema_id | +----+---------+------------+--------+--------+ | 1 | Juhan | 1935 | NULL | NULL | | 2 | Marta | 1938 | NULL | NULL | | 3 | Martin | 1970 | 1 | 2 | | 4 | Anne | 1974 | NULL | NULL | | 5 | Juku | 2005 | 3 | 4 | | 6 | Kati | 2003 | 3 | 4 | +----+---------+------------+--------+--------+ * Väljastage isikute eesnimed SELECT eesnimi FROM isikud; * Väljastage isikute ees- ja isanimed kui võimalik Tabelist isikud luuakse päringus kaks eksemplari. Üks nimega uuritavad, teine nimega isad. Ning uuritavate isa_id järgi kõrvutatakse külge isa rida isade tabelist. SELECT-osas määratakse, milliseid tulpi näidataks. SELECT uuritavad.eesnimi, isad.eesnimi as isanimi FROM isikud as uuritavad, isikud as isad WHERE uuritavad.isa_id=isad.id; +---------+---------+ | eesnimi | isanimi | +---------+---------+ | Martin | Juhan | | Juku | Martin | | Kati | Martin | +---------+---------+ * Väljastage inimeste ees-, isa- ja emanimed kui võimalik. Sarnane eelmise päringuga, ainult, et kolmas isikute tabeli koopia tuli juurde emade nime all. SELECT uuritavad.eesnimi, isad.eesnimi as isanimi, emad.eesnimi as emanimi FROM isikud as uuritavad, isikud as isad, isikud as emad WHERE uuritavad.isa_id=isad.id AND uuritavad.ema_id=emad.id; * Väljastage inimeste ees-, isa- ja emanimed kui võimalik. SELECT uuritavad.eesnimi, isad.eesnimi AS isanimi FROM isikud AS uuritavad LEFT JOIN isikud as isad ON uuritavad.isa_id=isad.id; +---------+---------+---------+ | eesnimi | isanimi | emanimi | +---------+---------+---------+ | Martin | Juhan | Marta | | Juku | Martin | Anne | | Kati | Martin | Anne | +---------+---------+---------+ * Väljastage kõikide eesnimed, isanimed nendel kel teada (LEFT JOIN) SELECT uuritavad.eesnimi, isad.eesnimi AS isanimi, emad.eesnimi AS emanimi FROM isikud AS uuritavad LEFT JOIN isikud AS isad ON uuritavad.isa_id=isad.id LEFT JOIN isikud AS emad ON uuritavad.ema_id=emad.id; +---------+---------+---------+ | eesnimi | isanimi | emanimi | +---------+---------+---------+ | Juhan | NULL | NULL | | Marta | NULL | NULL | | Martin | Juhan | Marta | | Anne | NULL | NULL | | Juku | Martin | Anne | | Kati | Martin | Anne | +---------+---------+---------+ * Väljastage, kui vana olid isa ja ema siis kui trükitav isik sündis. SELECT uuritavad.eesnimi, isad.eesnimi AS isanimi, emad.eesnimi AS emanimi, uuritavad.synniaasta-isad.synniaasta as isasyndimisel, uuritavad.synniaasta-emad.synniaasta as emasyndimisel FROM isikud AS uuritavad LEFT JOIN isikud AS isad ON uuritavad.isa_id=isad.id LEFT JOIN isikud AS emad ON uuritavad.ema_id=emad.id; +---------+---------+---------+---------------+---------------+ | eesnimi | isanimi | emanimi | isasyndimisel | emasyndimisel | +---------+---------+---------+---------------+---------------+ | Juhan | NULL | NULL | NULL | NULL | | Marta | NULL | NULL | NULL | NULL | | Martin | Juhan | Marta | 35 | 32 | | Anne | NULL | NULL | NULL | NULL | | Juku | Martin | Anne | 35 | 31 | | Kati | Martin | Anne | 33 | 29 | +---------+---------+---------+---------------+---------------+ * Väljastage inimesed, kelle isa on vanem kui ema SELECT uuritavad.eesnimi FROM isikud as uuritavad, isikud as isad, isikud as emad WHERE uuritavad.isa_id=isad.id AND uuritavad.ema_id=emad.id AND isad.synniaasta SELECT eesnimi, synniaasta FROM isikud; +---------+------------+ | eesnimi | synniaasta | +---------+------------+ | Juhan | 1935 | | Marta | 1938 | | Martin | 1970 | | Anne | 1974 | | Juku | 2005 | | Kati | 2003 | +---------+------------+ Edasi grupeerime nad sünniaastate kaupa. Kui mõnel aastal sündinuks mitu inimest, siis oleks nad ka selle aasta juures loetelus. SELECT GROUP_CONCAT(eesnimi), synniaasta as synniaeg FROM isikud GROUP BY synniaeg +-----------------------+----------+ | GROUP_CONCAT(eesnimi) | synniaeg | +-----------------------+----------+ | Juhan | 1935 | | Marta | 1938 | | Martin | 1970 | | Anne | 1974 | | Kati | 2003 | | Juku | 2005 | +-----------------------+----------+ Tahtes saada nimesid gruppi kümne aasta kaupa, arvutame sünnikümnendi. Jagame sünniaasta kümnega, võtame täisosa ning korrutame uuesti kümnega. Nii on ka 1938ndal aastal sündinud inimese sünnikümnend selle arvutuse põhjal 1930. Ning edasi saab juba selle tunnuse järgi grupeerida nii, et samal kümnendil sündinud inimesed samasse gruppi jäävad. SELECT GROUP_CONCAT(eesnimi), FLOOR(synniaasta/10)*10 as synniaeg FROM isikud GROUP BY synniaeg +-----------------------+----------+ | GROUP_CONCAT(eesnimi) | synniaeg | +-----------------------+----------+ | Juhan,Marta | 1930 | | Martin,Anne | 1970 | | Juku,Kati | 2000 | +-----------------------+----------+ * Leia inimese laste arv Kui tabelis oleks vaid lapsevanema_id, mitte isade või emade oma eraldi, siis käiks päring suhteliselt lihtsamalt. Tuleks vaid kokku lugeda iga andmerea puhul mitme rea pealt talle viidatakse. Kuna siin said tehtud isade ja emade viited eraldi, siis on ka arvutamist rohkem. Alustuseks kõik lapsed koos oma isade nimedega. SELECT isad.eesnimi, lapsed.eesnimi FROM isikud AS isad, isikud AS lapsed WHERE lapsed.isa_id=isad.id +---------+---------+ | eesnimi | eesnimi | +---------+---------+ | Juhan | Martin | | Martin | Juku | | Martin | Kati | +---------+---------+ Iga isa laste arv - kusjuures praegu uuritakse igalt isikult, mitmele inimesele ta isaks on. SELECT isad.eesnimi, (SELECT COUNT(*) FROM isikud AS lapsed WHERE lapsed.isa_id=isad.id) AS lastearv FROM isikud AS isad +---------+----------+ | eesnimi | lastearv | +---------+----------+ | Juhan | 1 | | Marta | 0 | | Martin | 2 | | Anne | 0 | | Juku | 0 | | Kati | 0 | +---------+----------+ Nüüd näidatakse välja vaid need, kel tõepoolest isana lapsi on. Nagu näha, tuli sama arvutus kahel korral kirja panna. Ühel korral arvutamiseks, teisel korral võrdlemiseks. Vajadusel saab selliseid toiminguid vahe- või abitabelite kaudu optimeerida. SELECT isad.eesnimi, (SELECT COUNT(*) FROM isikud AS lapsed WHERE lapsed.isa_id=isad.id) AS lastearv FROM isikud AS isad WHERE (SELECT COUNT(*) FROM isikud AS lapsed WHERE lapsed.isa_id=isad.id)>0; +---------+----------+ | eesnimi | lastearv | +---------+----------+ | Juhan | 1 | | Martin | 2 | +---------+----------+ Kõik laste ja vanemate vahelised seosed - olgu vanemaks siis isa või ema. SELECT lapsed.eesnimi, vanemad.eesnimi AS vanem FROM isikud AS lapsed, isikud AS vanemad WHERE lapsed.isa_id=vanemad.id OR lapsed.ema_id=vanemad.id; +---------+--------+ | eesnimi | vanem | +---------+--------+ | Martin | Juhan | | Martin | Marta | | Juku | Martin | | Juku | Anne | | Kati | Martin | | Kati | Anne | +---------+--------+ Sealt edasi saab kätte ka juba iga lapsevanema laste arvu ning laste nimed, mida me algul otsima hakkasime. SELECT vanemad.eesnimi AS vanem, COUNT(*) as laste_arv, GROUP_CONCAT(lapsed.eesnimi) as laste_nimed FROM isikud AS lapsed, isikud AS vanemad WHERE lapsed.isa_id=vanemad.id OR lapsed.ema_id=vanemad.id GROUP BY vanemad.id; +--------+-----------+-------------+ | vanem | laste_arv | laste_nimed | +--------+-----------+-------------+ | Juhan | 1 | Martin | | Marta | 1 | Martin | | Martin | 2 | Juku,Kati | | Anne | 2 | Juku,Kati | +--------+-----------+-------------+ Eelnenud päringut saab aga andmete leidmiseks edasi arendada. Nüüd on juures ka roll, et kas tegemisti isa või emaga. Tingimust aitab sõnadesse vormida if-käsklus. Eeldatakse, et kui vastav vanem ei ole lapsele isa, järelikult on ema. SELECT lapsed.eesnimi, IF(lapsed.isa_id=vanemad.id, 'isa', 'ema') AS roll , vanemad.eesnimi AS vanem FROM isikud AS lapsed, isikud AS vanemad WHERE lapsed.isa_id=vanemad.id OR lapsed.ema_id=vanemad.id; +---------+------+--------+ | eesnimi | roll | vanem | +---------+------+--------+ | Martin | isa | Juhan | | Martin | ema | Marta | | Juku | isa | Martin | | Juku | ema | Anne | | Kati | isa | Martin | | Kati | ema | Anne | +---------+------+--------+ Iga lapsevanema vanima lapse sünniaasta SELECT eesnimi, (SELECT MIN(synniaasta) FROM isikud AS lapsed WHERE lapsed.ema_id=vanemad.id OR lapsed.isa_id=vanemad.id) AS vanimalapsesynniaasta FROM isikud as vanemad; +---------+-----------------------+ | eesnimi | vanimalapsesynniaasta | +---------+-----------------------+ | Juhan | 1970 | | Marta | 1970 | | Martin | 2003 | | Anne | 2003 | | Juku | NULL | | Kati | NULL | +---------+-----------------------+ Veel lapsevanemaks mitte saanute andmete eemaldamiseks muudeti eelnev päring alampäringuks. Sellisel juhul ei pea vanima lapse sünniaastat võrdlemiseks uuesti välja arvutama, vaid saab tingimuseks kohe kirjutada WHERE vanimalapsesynniaasta IS NOT NULL. SELECT eesnimi, vanimalapsesynniaasta FROM (SELECT eesnimi, (SELECT MIN(synniaasta) FROM isikud AS lapsed WHERE lapsed.ema_id=vanemad.id OR lapsed.isa_id=vanemad.id) AS vanimalapsesynniaasta FROM isikud as vanemad) AS tabel1 WHERE vanimalapsesynniaasta IS NOT NULL; +---------+-----------------------+ | eesnimi | vanimalapsesynniaasta | +---------+-----------------------+ | Juhan | 1970 | | Marta | 1970 | | Martin | 2003 | | Anne | 2003 | +---------+-----------------------+ Kasutajad vastavalt huvialadele * Koosta päring, kus iga huviala juures näidatakse ära sellega seotud kasutajate arv. SELECT huviala_id, COUNT(*) AS kasutajate_arv FROM kasutajad_huvialad GROUP BY huviala_id; * Koosta päring, kus iga huviala juures näidatakse ära kõik kasutajanimed, kes selle huvialaga seotud on. SELECT huviala_id, GROUP_CONCAT(knimi) AS kasutanimed FROM kasutajad_huvialad, kasutajad WHERE kasutajad_huvialad.kasutaja_id=kasutajad.id GROUP BY huviala_id; Kuna kolm aktiivset kasutajat olid omale kõik neli huviala valinud, siis ongi nad igal pool loetelus. +------------+---------------------+ | huviala_id | kasutanimed | +------------+---------------------+ | 1 | zenja,detender,siim | | 2 | zenja,detender,siim | | 3 | detender,siim,zenja | | 4 | zenja,detender,siim | +------------+---------------------+ Tahtes ka huviala nime siia külge saada, on üheks võimaluseks esialgne päring muuta alampäringu abil tabeliks tabel1 ning sellega siduda huvialade tabel nõnda, et tabel1.huviala_id näitab huvialade tabeli id peale. Ning välimise SELECT-lausega siis määratakse, milliseid tulpi tegelikult näha tahetakse. SELECT huviala, kasutajanimed FROM (SELECT huviala_id, GROUP_CONCAT(knimi) AS kasutajanimed FROM kasutajad_huvialad, kasutajad WHERE kasutajad_huvialad.kasutaja_id=kasutajad.id GROUP BY huviala_id) as tabel1 JOIN huvialad ON tabel1.huviala_id=huvialad.id; +---------------+---------------------+ | huviala | kasutajanimed | +---------------+---------------------+ | Korvpall | zenja,detender,siim | | Jalgpall | zenja,detender,siim | | Ujumine | zenja,detender,siim | | Maratonijooks | zenja,detender,siim | +---------------+---------------------+ Üleslaadimised Lihtsaim üleslaadimise näide oli kirjas konspekti põhiosas. Juurde mõningaid vihjeid ja näiteid. Üleslaetavad failid ei pruugi sugugi olla vaid pildifailid. Kõiksugu nimedega faile ei või me vabalt veebikataloogi paigutada. Küll aga me võime inimesele salvestamise ajal soovitud failinime pakkuda. Järgnevas näites pannakse ükskõik milline üleslaetava faili sisu kausta nimega pildid, faili sisse andmed.dat. Ja faili nimega andmed.ini kirjutatakse selle faili algne nimi. Sellisel juhul on kasutajapoolsel faili küsimisel võimalik vana nimi säilitada. Failinime pakkumiseks on loodud päis kujul: Content-disposition: attachment; filename=teade.rtf kus siis teade.rtf-i asemel on pakutav nimi, mis praegusel juhul loetakse failist andmed.ini. Tingimusega kontroll, et kui on lehele seatud parameeter pildivaatamine, siis antakse tagasi eelnevalt salvestatud fail koos oma nimega. Faili laadimine

    Valitud faili laadimine

    Vaata faili: ".file_get_contents("pildid/andmed.ini").""; } ?> Vana nimega veebikataloogis Päisega failinime pakkumisel on puuduseks, et veebiserver ei lisa failitüüpi (nt. image/gif) ja brauseril võib olla raskusi õige tüübi aimamisel. Selle saab küll ise ka eraldi päisega kaasa kirjutada (Content-type: image/gif), kuid ise oma koodis kõikvõimalikke tüüpe meeles pidada on tülikavõitu. Lihtsam on lasta veebiserveril vastavat tuttavat tööd teha. Turvakaalutlustel on lubatavad laiendid piiratud. Kui laetaval failil on vastav laiend, siis ta paigutatakse kataloogi. Kui aga mitte, siis ei panda teda sinna. Edasi võib juba rahus veebikataloogis olevat faili vaadata. Faili laadimine

    Valitud faili laadimine

    Vaata faili: ".file_get_contents("pildid/andmed4.ini").""; } ?> Pildialbum * Koosta pildigalerii. Failid laetakse üles eraldi kataloogi ning sealt näidatakse veebilehele. Failid nummerdatakse 1.png, 2.png vastavalt kirje id-le andmebaasitabelis. Piltide juurde kuulub pealkiri. * Salvestatakse pildi üleslaadimise ajal olnud laiend (gif, jpg/jpeg või png). Näitamise ajal on pildil õige laiend küljes, failinimeks on ikka piltide tabeli vastava pildi id-number. * Pilte näidatakse lehel viie kaupa, nuppudega viited edasi ja tagasi. Pildiandmete tabelis hoidmiseks tuleb siis kõigepealt vastav tabel teha. Iga pildi kohta id-number, pildi pealkiri ja laiend. Pildi vana, üleslaadimisel olnud nime ei salvestata. CREATE TABLE pildid( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, pealkiri VARCHAR(255), laiend VARCHAR(4) ); Haldamise lehel saab valida faili. Kui vajutati lisamisnupule ja faili andmed jõudsid kohale, siis kõigepealt lisatakse rida andmebaasi – kasutaja pandud pildi pealkiri ning laiend. Loodud uue kirje id saab küsida muutujast $yhendus->insert_id. See number pannakse nüüd ka faili nimeks. Laiend jäetakse nii nagu on. Üles lubatakse laadida vaid gif, jpg ja png-lõppudega faile. piltidehaldus.php prepare("INSERT INTO pildid (pealkiri, laiend) VALUES (?, ?)"); $kask->bind_param("ss", $_REQUEST["pealkiri"],$laiend); $kask->execute(); if(move_uploaded_file($_FILES["pildifail"]["tmp_name"], "pildid/$yhendus->insert_id.$laiend")){ $teatesisu="fail lisatud"; } else { $teatesisu="Kopeerimisprobleem"; } } } } ?> Piltide haldus

    Pildi lisamine


    pealkiri:
    Piltide näitamiseks piisab andmebaasipäringust ning tsüklist, mis loob viited juba kataloogis leiduvatele piltidele. while($kask->fetch()){ echo "

    $pealkiri

    \n"; } Lehekülgede kaupa näitamiseks hoitakse eraldi muutujas $hulk kirjas piltide arvu näidataval lehel. Muutuja $algus näitab, mitmendast lehest alates pilte näitama hakatakse. Päring $kask=$yhendus->prepare("SELECT id, pealkiri, laiend FROM pildid ORDER BY id LIMIT $algus, $hulk"); annab välja pildid loendist alates elemendist $algus ning nii mitu tükki, kui palju näitab muutuja $hulk. MySQLi sõna LIMIT lihtsalt on selline õnnelik abiline. Leheküljenumbrite kuvamiseks sobib järgmine tsükkel: for($koht=0; $koht<$kogus; $koht+=$hulk){ if($koht==$algus){echo ($koht/$hulk+1)." ";} else {echo "".($koht/$hulk+1)." ";} } Arvutus $koht/$hulk näitab, et mitmenda leheküljega on tegemist – kui $koht on lehte alustava pildi järjekorranumber ning $hulk piltide arv lehel. Kuna selline loendamine algab nullist, siis tavainimesele tavalisemaks loendamiseks lisatakse leheküljenumbrile juurde 1. Kui on tegemist parasjagu ees oleva lehega, ehk siis $koht on võrdne lehe esimese pildi järjekorranumbrit näitava muutujaga $algus, sellisel juhul arvu viiteks ei muudeta – samale lehele pole ju vaja ehk uuesti minna. Muul juhul saab viitele vajutades sobiva alguspildi ette keerata nagu selle järjekorranumber viite parameetrina kaasa läheb. Edasi ja tagasi viited arvutavad vastavalt lehekülje jagu pildinumbreid sobivas suunas. Kui juba alustatakse pildist 0 ehk päris algusest, siis pole põhjust tagasiviidet aktiivseks teha. Kui aga tagantpoolt pole midagi vaadata (ehk $algus+$hulk on jõudnud piltide koguseni), siis jäetakse viide ”edasi” viitest ilma. piltidevaatamine.php prepare("SELECT COUNT(*) FROM pildid"); $kask->bind_result($kogus); $kask->execute(); $kask->fetch(); $kask->close(); $algus=0; if(isSet($_REQUEST["algus"])){ $algus=intval($_REQUEST["algus"]); } $hulk=2; $kask=$yhendus->prepare("SELECT id, pealkiri, laiend FROM pildid ORDER BY id LIMIT $algus, $hulk"); $kask->bind_result($id, $pealkiri, $laiend); $kask->execute(); ?> Piltide vaatamine

    Pildid

    tagasi "; } else { echo "tagasi "; } for($koht=0; $koht<$kogus; $koht+=$hulk){ if($koht==$algus){echo ($koht/$hulk+1)." ";} else {echo "".($koht/$hulk+1)." ";} } if($algus+$hulk<$kogus){ echo "edasi "; } else { echo "edasi "; } echo "
    "; while($kask->fetch()){ echo "

    $pealkiri

    \n"; } ?> Lisamine ja muutmine Kui toimetusi rohkem, siis on nad kasulik eraldi faili paigutada, siis jääb näidatav fail lihtsamaks ja puhtamaks. Näites siis lisamine, küsimine, muutmine ka kustutamine eraldi funktsioonidena. Samuti eraldi funktsioon veebilehele saabuva sisendi töötlemiseks, kus analüüsitakse saabuvaid parameetreid ning otsustatakse, et kas ja milline toimetus tuleb käivitada. abifunktsioonid.php prepare("INSERT INTO pildid (pealkiri, laiend) VALUES (?, ?)"); $kask->bind_param("ss", $_REQUEST["pealkiri"],$laiend); $kask->execute(); if(move_uploaded_file($_FILES["pildifail"]["tmp_name"], "pildid/$yhendus->insert_id.$laiend")){ $teatesisu="fail lisatud"; } else { $teatesisu="Kopeerimisprobleem"; } } return $teatesisu; } function kysiPildid(){ global $yhendus; $kask=$yhendus->prepare("SELECT id, pealkiri, laiend FROM pildid"); $kask->bind_result($id, $pealkiri, $laiend); $kask->execute(); $hoidla=array(); while($kask->fetch()){ $pilt=new stdClass(); $pilt->id=$id; $pilt->pealkiri=$pealkiri; $pilt->laiend=$laiend; array_push($hoidla, $pilt); } return $hoidla; } function kysiPilt($id){ global $yhendus; $kask=$yhendus->prepare("SELECT pealkiri, laiend FROM pildid WHERE id=?"); $kask->bind_param("i", $id); $kask->bind_result($pealkiri, $laiend); $kask->execute(); $kask->fetch(); $pilt=new stdClass(); $pilt->id=$id; $pilt->pealkiri=$pealkiri; $pilt->laiend=$laiend; $kask->close(); return $pilt; } function muudaPilt($id, $pealkiri, $failimas){ global $yhendus; $pilt=kysiPilt($id); if(strlen($failimas["name"])>0){ unlink("pildid/$pilt->id.$pilt->laiend"); $failiandmed=pathinfo($failimas["name"]); $laiend=$failiandmed["extension"]; move_uploaded_file($failimas["tmp_name"], "pildid/$id.$laiend"); $kask=$yhendus->prepare("UPDATE pildid SET pealkiri=?, laiend=? WHERE id=?"); $kask->bind_param("ssi", $pealkiri, $laiend, $id); } else { $kask=$yhendus->prepare("UPDATE pildid SET pealkiri=? WHERE id=?"); $kask->bind_param("si", $pealkiri, $id); } $kask->execute(); } function kustutaPilt($id){ global $yhendus; $pilt=kysiPilt($id); @unlink("pildid/$pilt->id.$pilt->laiend"); $kask=$yhendus->prepare("DELETE FROM pildid WHERE id=?"); $kask->bind_param("i", $id); $kask->execute(); } function tootleSisend(){ if(isSet($_REQUEST["lisamine"])){ return lisaPilt(); } if(isSet($_REQUEST["muutmisid"])){ muudaPilt($_REQUEST["muutmisid"], $_REQUEST["pealkiri"], $_FILES["pildiandmed"]); } if(isSet($_REQUEST["kustutusid"])){ kustutaPilt($_REQUEST["kustutusid"]); } return ""; } ?> Põhifaili juures saab sel juhul mõnekümne koodireaga piiluda. Abifunktsioonide failist loetakse sisse vajalikud käsklused. Palutakse töödelda sisend ning küsitakse näidatavate piltide loetelu. Edasi vaja nad ainult lehele mugavalt paigutada ning muutmise/kustutamise tarbeks viited külge paigutada. piltidehaldus2.php Piltide haldus Pildi muutmine
    Pealkiri:

    "; } ?>

    Pildi lisamine


    pealkiri:

    $pilt->pealkiri

    k m "; } ?> Kui kood töös, siis tuleb vaid sobivad pildid galeriisse üles seada.