Kirjoittaja: Antti Laaksonen [antti.laaksonen@mbnet.fi]
Paitsi että funktioita käyttämällä koodin pituus pienenee, ne myös tekevät siitä selkeämmän ja helpottavat virheenkorjausta. Tämä opas sisältää perusasiat funktioiden luomisesta PHP-kielessä. Oppaan lopussa on esimerkkiprojekti, vieraskirja, jossa yhdistyvät opassarjan edellisten osien opetukset.
Funktion määrittely
Funktion määrittely aloitetaan avainsanalla function. Tämän jälkeen kirjoitetaan funktion nimi ja sulkumerkit. Funktion lausekkeet laitetaan aaltosulkujen sisään. Seuraavassa esimerkissä funktio rivi tulostaa rivin tekstiä. Funktiota kutsutaan kolmesti.
<?php
function rivi() {
echo "Tämä tuli funktiosta!\n";
}
echo "Ensimmäinen rivi.\n";
rivi();
rivi();
rivi();
echo "Viimeinen rivi.";
//Ensimmäinen rivi.
//Tämä tuli funktiosta!
//Tämä tuli funktiosta!
//Tämä tuli funktiosta!
//Viimeinen rivi.
?>
Funktion parametrit
Hyvin usein funktiolle annetaan myös parametreja. Parametrit ovat muuttujia, jotka vaikuttavat funktion toimintaan. Parametrit kirjoitetaan funktion nimen perässä olevien sulkumerkkien sisään pilkuilla erotettuina. Ne ovat käytössä funktion sisällä samannimisinä muuttujina.
<?php
function tiedot($nimi, $kaupunki) {
echo "$nimi asuu {$kaupunki}ssa.\n";
}
tiedot("Pentti", "Kuopio");
tiedot("Seppo", "Espoo");
//Pentti asuu Kuopiossa.
//Seppo asuu Espoossa.
?>
Funktion parametreilla voi olla oletusarvoja, joita käytetään silloin, jos parametria ei ole annettu. Oletusarvot määritellään yhtäsuuruusmerkin avulla. Kuitenkin vain viimeiset parametrit voivat olla valinnaisia (muuten parametrit voisivat mennä sekaisin). Seuraavassa esimerkissä nimi on oletuksena "Nimetön".
<?php
function tervehdys($nimi = "Nimetön") {
echo "Moi, $nimi!\n";
}
tervehdys();
tervehdys("Pentti");
tervehdys("Seppo");
//Moi, Nimetön!
//Moi, Pentti!
//Moi, Seppo!
?>
Funktion palautusarvo
Monesti funktio palauttaa arvon, jota voidaan käyttää hyväksi funktiota kutsuneessa koodissa. Tämä tapahtuu return-avainsanan avulla. Tämän jälkeen funktiosta poistutaan välittömästi. Seuraavassa esimerkissä euroiksi-funktio jakaa markkamäärän euron kurssilla ja pyöristää tuloksen kahden desimaalin tarkkuudelle round-funktiolla.
<?php
function euroiksi($markat) {
return round($markat / 5.94573, 2);
}
echo "100 markkaa on " . euroiksi(100) . " euroa.";
//100 markkaa on 16.82 euroa.
?>
Muuttujat funktiossa
Jos funktiossa halutaan käyttää funktion ulkopuolella olevia muuttujia, ne on määriteltävä global-avainsanan avulla. Avainsanan perään kirjoitetaan yhden tai useamman muuttujan nimi pilkuilla erotettuina. Seuraavassa esimerkissä markan ja euron suhde haetaan funktion ulkopuolisesta muuttujasta.
<?php
$suhde = 5.94573;
function euroiksi($markat) {
global $suhde;
return round($markat / $suhde, 2);
}
echo "100 markkaa on " . euroiksi(100) . " euroa.";
?>
Funktion virheenkäsittely
Tavallisesti funktiossa tapahtuvat virhetilanteet tuottavat virheilmoituksen aivan samoin kuin muuallakin koodissa. Oudot virheilmoitukset voivat kuitenkin aiheuttaa päänvaivaa skriptin käyttäjälle, minkä vuoksi ilmoitusten tulostuminen halutaan välillä estää. Tämä on mahdollista kirjoittamalla merkki @ funktion nimen eteen.
<?php
function jako() {
//jako nollalla aiheuttaisi tavallisesti ilmoituksen "Division by zero"...
$osamaara = 10 / 0;
}
//...mutta koska funktion nimen edessä on @, virheilmoitus ei tule näkyviin
@jako()
?>
On kuitenkin syytä muistaa, että tärkeät, korjausta vaativat virheet voivat samalla jäädä näkemättä. Eräs hyvä keino virheenkäsittelyyn on hyödyntää funktioiden palautusarvoja. Seuraavassa esimerkissä tiedoston rivit luetaan taulukkoon. Jos lukeminen ei onnistunut, muuttujan arvo on false, jolloin näytetään suomenkielinen virheilmoitus.
<?php
$tiedosto = @file("olematon.xyz");
if ($tiedosto) {
//tähän tulee tiedoston rivien käsittely
} else {
echo "Tiedoston lukeminen epäonnistui!";
}
?>
Villen vieraskirja
Opassarjan neljännessä esiintyi kuvitteellinen Villen korttipelisivu, jossa PHP:ta käytettiin sivupohjissa ja palautteen lähettämisessä. Villen PHP-taidot ovat karttuneet ja hän päätti tehdä itse sivuilleen vieraskirjan, johon kävijät voivat lähettää palautetta ja terveisiä. Nyt tutkimme askel askeleelta, kuinka Ville rakensi vieraskirjansa.
Vieraskirjan rakenne
Viestit on tallennettu tiedostoon viestit.txt, joka on tavallinen tekstitiedosto. Jokainen viesti on omalla rivillään ja viestiä kohden on seuraavat tiedot: lähettäjän nimi, lähettäjän sähköpostiosoite, lähetysaika ja viesti. Nämä tiedot on erotettu pystyviivoilla (|), joten tiedoston rakenne näyttää seuraavalta:
nimi1|email1|aika1|viesti1
nimi2|email2|aika2|viesti2
nimi3|email3|aika3|viesti3
Vieraskirja on melko yksinkertainen, joten sen käsittelyyn riittää kaksi skriptiä:
Viestien näyttäminen
Tiedosto nayta.php alkaa tavallisella HTML-koodilla, joka sisältää otsikon ja linkin viestin lähetyssivulle.
<html>
<head>
<title>Vieraskirja</title>
</head>
<body>
<h1>Vieraskirja</h1>
<p><a href="laheta.php">Lähetä viesti</a></p>
Tämän jälkeen tulee PHP-osuus. Aluksi viestit luetaan taulukkoon file-funktiolla ja taulukko käännetään ympäri array_reverse-funktiolla. Koska viestit tallennetaan tiedoston loppuun, uusimmat viestit ovat nyt taulukon alussa. Viestien määrä on sama kuin tiedoston rivien määrä, joten se selviää count-funktiolla.
Kun viestien määrä tiedetään, niiden läpikäyminen on helppoa for-silmukalla. Jokaisessa taulukon alkiossa on tiedostosta luettu rivi, joka sisältää viestin tiedot pystyviivoilla erotettuna. Tämä merkkijono muutetaan nelialkioiseksi taulukoksi explode-funktion avulla. Funktio saa parametreikseen erotinmerkin, merkkijonon ja alkioiden määrän.
Taulukosta tiedot siirretään muuttujiin. Tämän jälkeen viesti on valmis tulostettavaksi sopivasti muotoiltuna. Viestin lähetysaika on tallennettu aikaleimana (numerosarja, joka kuvaa kuluneiden sekuntien määrää tammikuun 1. päivästä 1970), ja se muunnetaan ymmärrettävämpään muotoon date-funktion avulla. Muotoilumerkkijono "d.m.Y H:i" saa aikaan suomalaisen päivämäärän.
<?php
//luetaan viestit taulukkoon
$viestit = file("viestit.txt");
//käännetään taulukko, jolloin uusimmat viestit tulevat ylimmiksi
$viestit = array_reverse($viestit);
//viestien määrä on suoraan taulukon rivien määrä
$viestimaara = count($viestit);
//tulostetaan viestimäärä
echo "<p>Yhteensä <b>$viestimaara</b> viestiä.</p><hr>";
//käydään jokainen viesti läpi
for ($i = 0; $i < $viestimaara; $i++) {
//$viestit[$i] on merkkijono, joka sisältää viestin $i tiedot
//pystyviivoilla erotettuna; jaetaan viestit $tiedot-taulukkoon
$tiedot = explode("|", $viestit[$i], 4);
//erotellaan tiedot omiin muuttujiinsa
$nimi = $tiedot[0];
$email = $tiedot[1];
$aika = $tiedot[2];
$viesti = $tiedot[3];
//tulostetaan viesti
echo "<p><b>Lähettäjä</b>: <a href=\"mailto:$email\">$nimi</a><br>";
echo "<b>Aika</b>: " . date("d.m.Y H:i", $aika) . "<br>";
echo "<br>$viesti<hr>";
}
?>
Loppuun tulee vielä pari riviä HTML-koodia, jotka päättävät sivun.
</body>
</html>
Viestin lähettäminen
Viestin lähettämisessä on kaksi vaihetta: käyttäjä kirjoittaa viestin ja skripti tallentaa sen tiedostoon. Tässä vieraskirjassa kumpikin vaihe on jaettu samaan tiedostoon, laheta.php. Koko skriptin pohjana on itse asiassa suuri if-ehtolause, joka määrittää, näytetäänkö viestin kirjoittamiseen tarkoitettu lomake, vai onko jo aika tallentaa viesti tiedostoon.
<?php
//jos nimeä ei ole annettu, näytetään lomake...
if (!isset($_POST['nimi'])) {
?>
Jos lomakkeen kautta ei tullut muuttujaa nimeä, lomaketta ei vielä oltu lähetetty (tai käyttäjä ei ollut laittanut nimeään, jolloin viestin tallentaminen ei myöskään käy). Tällöin näytetään lomake, joka sisältää tekstikentät nimelle, sähköpostille ja viestille sekä lähetysnapin.
<html>
<head>
<title>Viestin lähetys</title>
</head>
<body>
<h1>Viestin lähetys</h1>
<form action="laheta.php" method="post">
Nimi: <br> <input type="text" name="nimi"> <br>
Sähköposti: <br> <input type="text" name="email"> <br>
Viesti: <br> <textarea name="viesti"></textarea> <br> <br>
<input type="submit" value="Lähetä">
</form>
</body>
</html>
Jos lomake olikin jo lähetetty, on aika tallentaa uusi viesti tiedostoon. Tiedosto avataan append-tilassa, jolloin uusi viesti kirjoitetaan vanhojen viestien perään. Tämän jälkeen lomakkeen kautta tulleet tiedot haetaan muuttujiin.
Ennen kuin viestin voi tallentaa tiedostoon, siihen on tehtävä muutamia muutoksia:
stripslashes-funktiolla.
htmlspecialchars-funktiolla.
str_replace-funktion avulla. Samalla viesti mahtuu yhdelle riville tiedostossa.
Viestin lähetysaika selviää time-funktiolla, joka palauttaa palvelimen ajan aikaleimana. Näin tallennettuna ajan muotoilua on helppo vaihtaa myöhemmin. Tämän jälkeen tiedoista muodostetaan pystyviivoilla erotettu rivi, joka tallennetaan tiedostoon. Lopuksi käyttäjä ohjataan takaisin vieraskirjasivulle header-funktion avulla.
<?php
//...muussa tapauksessa kirjoitetaan viesti tiedostoon
} else {
//avataan tiedosto append-tilassa: kirjoitetaan tiedoston loppuun
$tiedosto = fopen("viestit.txt", "a");
//haetaan lomakkeen kautta tulleet muuttujat
$nimi = $_POST['nimi'];
$email = $_POST['email'];
$viesti = $_POST['viesti'];
//poistetaan ylimääräiset kenoviivat (\)
$viesti = stripslashes($viesti);
//estetään HTML-tagien käyttäminen
$viesti = htmlspecialchars($viesti);
//muutetaan rivinvaihdot HTML-muotoon
$viesti = str_replace("\n", "<br>", $viesti);
//otetaan talteen aika, jolloin viesti lähetettiin
$aika = time();
//muodostetaan tiedostoon tallennettava rivi
$rivi = "$nimi|$email|$aika|$viesti\n";
//kirjoitetaan rivi tiedostoon
fwrite($tiedosto, $rivi);
//suljetaan tiedosto
fclose($tiedosto);
//ohjataan käyttäjä vieraskirjasivulle
header("Location: nayta.php");
}
?>
Loppusanat
Ville kopioi palvelimelle PHP-tiedostot sekä tyhjän viestitiedoston. Viestitiedon chmod-arvoksi hän asetti 664, jotta sen muokkaaminen PHP:n kautta onnistuu. Myöhemmin Ville lisäsi vieraskirjaansa vielä viestien sivutuksen ja itselleen mahdollisuuden vastata viesteihin. Omien skriptien tekeminen onkin paras tapa oppia PHP.
Opassarjan seuraavaan osa ilmestyy joidenkin viikkojen kuluttua. Aiheita ovat ainakin evästeiden käyttö, sivujen salasanasuojaus ja tiedostojen kopiointi selaimen kautta. Kenties jokin vähän suurempi esimerkkiskriptikin mahtuu mukaan. osa 7
Antti Laaksonen, 21.5.2003