OPPITUNTI 21 Palvelinympäristö

Samankaltaiset tiedostot
OPPITUNTI 10 Tiedostojen käsittely

OPPITUNTI 11 DBM-funktioiden käyttö

6. Funktiot 85. Kuinka funktioita määritellään ja kutsutaan. Kuinka funktioille viedään arvoja ja niistä palautetaan arvoja

OPPITUNTI 3 Ensimmäinen skripti

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Ohjelmoinnin perusteet Y Python

OPPITUNTI 20 Tilan tallentaminen istuntofunktioilla

Taustaa. CGI-ohjelmointi

Metropolia Ammattikorkeakoulu

Luento 4. Timo Savola. 21. huhtikuuta 2006

OPPITUNTI 5 Ohjelman kulku

Hieman linkkejä: lyhyt ohje komentoriviohjelmointiin.

Korpusten käsittely clt131, P Luento 4

Harjoitustyö: virtuaalikone

Korpusten käsittely clt131, P Luento 5

Harjoituksen aiheena on tietokantapalvelimen asentaminen ja testaaminen. Asennetaan MySQL-tietokanta. Hieman linkkejä:

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 6: Python

Pythonin Kertaus. Cse-a1130. Tietotekniikka Sovelluksissa. Versio 0.01b

Luento 5. Timo Savola. 28. huhtikuuta 2006

Ohjelmoinnin perusteet Y Python

OPPITUNTI 16 Tiedon käsittely

VERKKOSOVELLUSTEN OHJELMOINTI, JOHDATUS PHP:HEN

OSA III PHP:n käyttö. Oppitunti

OPPITUNTI15 Päivämäärien käsittely

ATK tähtitieteessä. Osa 4 - IDL input/output. 19. syyskuuta 2014

2 Konekieli, aliohjelmat, keskeytykset

8. Oliot 123. Kuinka luokkia luodaan ja olioita saadaan aikaan. Kuinka luodaan ja käsitellään ominaisuuksia ja metodeja

13. Pintaa syvemmältä 233

Kieliteknologian ATK-ympäristö Viides luento

ASCII-taidetta. Intro: Python

Kieliteknologian ATK-ympäristö Viides luento

[Jnix näyttökoe. o ei ole sallittua käyttää mitään verkkolevyjakoa tai mitään siihen rinnastettavaa järjestelmdä.

Ohjelmoinnin perusteet Y Python

3.1 Mitä tarkoittaan heredoc? Milloin sitä kannattaa käyttää? Kirjoita esimerkki sen käyttämisestä.

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Verkkosivut perinteisesti. Tanja Välisalo

Maastotietokannan torrent-jakelun shapefile-tiedostojen purkaminen zip-arkistoista Windows-komentojonoilla

LINUX-HARJOITUS, MYSQL

TAMPEREEN TEKNILLINEN YLIOPISTO Digitaali- ja tietokonetekniikan laitos. Harjoitustyö 4: Cache, osa 2

Tiedostot. Tiedostot. Tiedostot. Tiedostot. Tiedostot. Tiedostot

Komentotulkki. Kysymyksiä

Palvelinpuolen ohjelmointi

OPPITUNTI 24 Esimerkki (Osa 2)

XML prosessori. XML prosessointi. XML:n kirjoittaminen. Validoiva jäsennin. Tapahtumaohjattu käsittely. Tapahtumaohjattu käsittely.

811120P Diskreetit rakenteet

Unix-perusteet. Unix/Linux-käyttöjärjestelmä ja sen ominaisuudet

Unix. Markus Norrena

Johdatus Ohjelmointiin

Matriisit ovat matlabin perustietotyyppejä. Yksinkertaisimmillaan voimme esitellä ja tallentaa 1x1 vektorin seuraavasti: >> a = 9.81 a = 9.

Osa. Listaus 2.1. HELLO.CPP esittelee C++ -ohjelman osat. 14: #include <iostream.h> 15: 16: int main() 17: {

OPPITUNTI 12 MySQL-tietokannan käyttö

OPPITUNTI 19 Tilan tallentaminen evästeiden ja kyselymerkkijonojen avulla

SeaMonkey pikaopas - 1

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:

SQL Buddy JAMK Labranet Wiki

Luento 3. Timo Savola. 7. huhtikuuta 2006

Juricon Nettisivu Joomlan käyttöohjeet

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

PHP:n alkeita ja taustaa. Markus Norrena

Käytin tehtävän tekemiseen Xubuntu käyttöjärjestelmää aikaisemmin tekemältäni LiveUSB-tikulta.

Ctl160 Tekstikorpusten tietojenkäsittely Kolmas luento,

7. Taulukot 105. Kuinka taulukoiden tietoa käsitellään ja lajitellaan

Zeon PDF Driver Trial

JavaScript alkeet Esimerkkikoodeja moniste 2 ( Metropolia)

Luento 2. Timo Savola. 31. maaliskuuta 2006

Tietojen syöttäminen ohjelmalle. Tietojen syöttäminen ohjelmalle Scanner-luokan avulla

Julkinen. Suomen Pankin ja Finanssivalvonnan suojattu sähköposti: ulkoisen käyttäjän ohje

Webmailin käyttöohje. Ohjeen sisältö. Sähköpostin peruskäyttö. Lomavastaajan asettaminen sähköpostiin. Sähköpostin salasanan vaihtaminen

Ohjelmoinnin perusteet Y Python

Kieliversiointityökalu Java-ohjelmistoon. Ohje

Kun tulostuksessa ilmenee muotoiluvirheitä

Kirje -tasolla viestiliikenne suojataan automaattisesti SSL-salauksella, sekä viesti lukitaan Deltagon MessageLock -tekniikalla.

Visma Business AddOn Tuotetarrat. Käsikirja

Ohjelmoinnin perusteet Y Python

Julkaiseminen verkossa

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

PERL. TIE Principles of Programming Languages. Ryhmä 4: Joonas Lång & Jasmin Laitamäki

SELVITYSRAPORTTI LABRA-VERKON MYSQL:n JA PHP:n KÄYTTÖÖNOTOSTA. Jarkko Kähkönen

OPPITUNTI 14 Dynaamisten kuvien käsittely

Nettiposti. Nettiposti käyttöohje

Valintanauhan komennot Valintanauhan kussakin välilehdessä on ryhmiä ja kussakin ryhmässä on toisiinsa liittyviä komentoja.

Ohjelmoinnin perusteet Y Python

Julkaiseminen verkossa, esitysgrafiikkaa (laitteistosta, tietotekniikka ja tulevaisuus) H9T1: Tiedostojen vienti internetiin

Komentotulkki (SHELL) C- "perhe" - csh, alkup. C shell. Komentokieli. kieltä. - tcsh - edellisen laajennettu versio

Luottamuksellinen sähköposti Lapin yliopistossa. Ilmoitusviesti

Kotisivuohjeet. Eteläpohjalaiset Kylät ry. Sivupohjien rakenne

Pong-peli, vaihe Aliohjelman tekeminen. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana

linux linux: käyttäjän oikeudet + lisää ja - poistaa oikeuksia

2 3 LIITE 2. Index.php 1 (10) 4 5 <?php 6 7 /*! \mainpage Artikkelihallintaohjelma 8 * 9 * \section intro_sec Introduction 10 * 11 * Tämän on

Kieliteknologian ATK-ympäristö Neljäs luento

Google Cloud Print -opas

Yksityiskohtaiset ohjeet. TwinSpacen käyttäminen

811120P Diskreetit rakenteet

Pikaopas. Ohjeiden etsiminen Hae ohjesisältöä napsauttamalla kysymysmerkkiä.

Using the QGIS Browser

Transkriptio:

21. Palvelinympäristö 365 OPPITUNTI 21 Palvelinympäristö Edellisellä tunnilla tutkimme tekniikoita, joiden avulla voidaan kommunikoida etäkoneiden kanssa ja saada tietoa käyttäjiltä. Tällä tunnilla käsittelemme ympäristöä uudelleen, nyt tutkimme tekniikoita, joita käyttäen voidaan ajaa ulkoisia ohjelmia omalla koneella. Tämän tunnin esimerkit on laadittu Linux-ympäristöön, mutta periaatteet ovat samat myös Windows-ympäristössä. Tämän tunnin aiheita ovat Kuinka tietoa voidaan putkittaa menemään ulkoisille sovelluksille ja kääntäen Muita keinoja lähettää shell-komentoja ja esittää tuloksia selaimella Turvallisuusnäkökohdat PHP-skripteistä käsin suoritettavissa sisäisissä prosesseissa

366 21. Palvelinympäristö Putkien avaaminen prosesseihin popen()-funktiolla Aivan samalla lailla kuin avaat tiedoston kirjoittamista tai lukemista varten fopen()-funktiolla, voit avata putken prosessiin popen()-funktiolla. Funktio ottaa argumentikseen polun komentoon ja merkkijonon, joka edustaa moodia (luku tai kirjoitus). Funktio palauttaa tiedosto-osoittimen, jota voidaan käyttää samalla lailla kuin fopen()-funktion palauttamaa tiedosto-osoitinta. Voit viedä popen()-funktiolle toisen kahdesta moodilipusta, jotka ovat "w" (kirjoitus prosessiin) ja "r" (luku prosessista). Et voi sekä kirjoittaa prosessiin että lukea prosessista saman yhteyden aikana. Kun olet lopettanut työsi popen()-funktion tiedosto-osoittimen avulla, sinun on suljettava yhteys kutsumalla pclose()-funktiota, joka vaatii sopivan tiedosto-osoittimen. Lukeminen popen()-prosessista on hyödyllistä, kun haluat jäsennellä tulostuksen prosessista rivi riviltä. Listaus 21.1 avaa yhteyden who-komennon GNUversioon ja jäsentelee sen tulostuksen ja lisää mailto-linkin kullekin käyttäjänimelle. Listaus 21.1 Unixin who-komennon tulostuksen lukeminen popen()-funktiolla 1: <html> 2: <head> 3: <title>listing 21.1 Using popen() to read the 4: output of the UNIX who command</title> 5: </head> 6: <body> 7: <h2>administrators currently logged on to the server</h1> 8: <?php 9: $ph = popen( "who", "r" ) 10: or die( "Couldn't open connection to 'who' command" ); 11: $host="zink.demon.co.uk"; 12: while (! feof( $ph ) ) 13: { 14: $line = fgets( $ph, 1024 ); 15: if ( strlen( $line ) <= 1 ) 16: continue; 17: $line = ereg_replace( "^([a-za-z0-9_\-]+).*", 18: "<a href=\"mailto:\\1@$host\">\\1</a><br>\n", 19: $line ); 20: print "$line"; 21: } 22: pclose( $ph ); 23:?>

21. Palvelinympäristö 367 24: </table> 25: </body> 26: </html> Saimme tiedosto-osoittimen popen()-funktiolla ja käytimme sitten while-lausetta jokaisen rivin lukemiseksi prosessin tuottamasta tulostuksesta. Jos tuotos on yksittäinen merkki, hyppäämme loppuosan yli. Muutoin käytämme ereg_replace()-funktiota HTML-linkin ja taulukon solujen lisäämiseen merkkijonoon ennen riviä. Lopuksi suljemme yhteyden pclose()-funktiolla. Kuva 21.1 esittää näytetulostuksen listauksesta 21.1. KUVA 21.1 UNIX:in whokomennon tulostuksen lukeminen. Voit käyttää popen()-funktion avaamaa yhteyttä myös prosessiin kirjoittamiseen. Se on hyödyllistä komennoille, jotka ottavat argumenteikseen tietoa standardista syöttölaitteesta ja myös komentoriviargumenteista. Listaus 21.2 avaa yhteyden column-sovellukseen popen()-funktiolla. Listaus 21.2 Tiedon vieminen column-sovellukselle popen()-funktiolla 1: <html> 2: <head> 3: <title>listing 21.2 Using popen() to pass 4: data to the column command</title> 5: </head> 6: <body> 7: <?php 8: $products = array(

368 21. Palvelinympäristö 9: array( "HAL 2000", 2, "red" ), 10: array( "Tricorder", 3, "blue" ), 11: array( "ORAC AI", 1, "pink" ), 12: array( "Sonic Screwdriver", 1, "orange" ) 13: ); 14: $ph = popen( "column -tc 3 -s / > purchases/user3.txt", "w" ) 15: or die( "Couldn't open connection to 'column' command" ); 16: foreach ( $products as $prod ) 17: fputs( $ph, join('/', $prod)."\n"); 18: pclose( $ph ); 19:?> 20: </table> 21: </body> 22: </html> Listauksen 21.2 tarkoituksena on ottaa moniulotteisen taulukon elementit ja tulostaa ne tiedostoon ASCIItaulukkona. Avaamme yhteyden column-komentoon ja lisäämme mukaan komentoriviargumentteja. Argumentti -t vaatii, että tulostus muotoillaan taulukoksi, -c 3 määrittää sarakkeiden määrän ja -s / asettaa "/"-merkin kenttäerottimeksi. Varmistamme, että tulokset kirjoitetaan tiedostoon nimeltä user3.txt. Huomaa, että ostoskansion on oltava olemassa ja että skriptin tulee voida kirjoittaa siihen. Huomaa, että teemme tällä komennolla useamman kuin yhden asian. Kutsumme column-komentoa ja kirjoitamme tulostuksen tiedostoon. Itse asiassa suoritamme komentoja ei-vuorovaikutteisessa shellissä. Sen lisäksi, että putkitamme sisällön prosessiin, voimme alustaa myös muita prosesseja. Voimme vaikkapa lähettää column-komennon tulostuksen sähköpostilla: popen( "column -tc 3 -s / mail matt@zink.demon.co.uk", "w" ) Tällainen joustavuus voi kaataa järjestelmämme hautaan, jos viemme käyttäjän syöttämän tiedon PHPfunktiolle, joka suorittaa shell-komentoja. Tutkimme varoituksia ennen tämän tunnin päättämistä. Kun tiedosto-osoitin on saatu, käymme silmukassa läpi $product-taulukon. Jokainen arvo on itse taulukko, jonka voimme muuntaa merkkijonoksi käyttämällä join()-funktiota. Sen sijaan, että yhdistämme välilyöntimerkin mukaan, käytämme yhdistämisessä komentoriviargumenttina annettua "/"-merkkiä. Sen käyttäminen on välttämätöntä taulukon kohdalla, koska välilyönnit hämäisivät column-komentoa. Kun taulukko on yhdistetty, viedään tulosmerkkijono ja rivinvaihtomerkki fputs()-funktiolle. Lopuksi suljemme yhteyden. Nyt user3.txt-tiedosto sisältää nätisti muotoiltua tietoa: HAL 2000 2 red Tricorder 3 blue ORAC AI 1 pink

21. Palvelinympäristö 369 Sonic Screwdriver 1 orange Voisimme tehdä koodista siirrettävämpää muotoilemalla tekstin sprintf()-funktiolla, ja voitkin halutessasi tehdä niin. Komentojen ajaminen exec()-funktiolla Komentoja voidaan viedä shell-kerrokselle myös exec()-funktiolla. Funktio ottaa argumentikseen merkkijonon, jossa on ajettavan komennon tiedostopolku. Se ottaa myös valinnaisen argumentin, joka on taulukkomuuttuja, johon komennon tuottama tulostus voidaan sijoittaa, sekä toisen valinnaisen argumentin, johon sijoitetaan komennon palautusarvo. Saadaksemme esimerkiksi listauksen nykyisestä työhakemistosta, voimme viedä exec()-funktiolle merkkijonon "ls -al". Teemme niin listauksessa 21.3 ja tulostamme tuloksen selaimelle. Listaus 21.3 Hakemistolistauksen tuottaminen exec()-funktiolla 1: <html> 2: <head> 3: <title>listing 21.3 Using exec() to produce a directory listing</title> 4: </head> 5: <body> 6: <?php 7: exec( "ls -al.", $output, $return ); 8: print "<p>returned: $return</p>"; 9: foreach ( $output as $file ) 10: print "$file<br>"; 11:?> 12: </table> 13: </body> 14: </html> Huomaa, että ls-komento palauttaa arvon nolla, jos se onnistuu tehtävässään. Jos emme löydä kansiota tai emme voi lukea sitä, komento palauttaa arvon yksi. Olemme jälleen kerran keksineet pyörän uudelleen, ainakin osan siitä. Olisimme voineet käyttää opendir()- ja readdir()-funktioita hakemistolistauksen esittämiseen. On kuitenkin tilanteita, joissa järjestelmän komennolla saadaan aikaan toimintoja, joiden toteuttaminen PHP-koodilla olisi todella työlästä. Olet saattanut joskus luoda shell- tai Perl-skriptin tekemään monimutkaisen tehtävän. Jos kehittämisnopeus

370 21. Palvelinympäristö on tärkeää projektissasi, saatat harkita ulkoisen skriptin käyttämistä sen sijaan, että muokkaisit sen PHPmuotoon. Muista kuitenkin, että ulkoisen prosessin kutsuminen kuluttaa useimmiten lisää aikaa ja muistia. Kuva 21.2 esittää listauksen 21.3 tulostuksen. KUVA 21.2 Hakemistolistaus exec()-funktiolla. Ulkoisten komentojen ajaminen system()-funktiolla tai heittomerkkioperaattorilla Edellä esiteltyä exec()-funktiota muistuttava system()-funktio käynnistää sekin ulkoisen sovelluksen. Se ottaa argumentikseen komennon ja valinnaisen muuttujan, johon komennon palauttama arvo tallennetaan. Funktio tulostaa shell-komennon tuotoksen suoraan selaimelle. Seuraava koodi tulostaa man-komennon manuaalisivun: <?php print "<pre>"; system( "man man col -b", $return ); print "</pre>";?> Koodissa käytetään PRE-tageja, jotta selain voisi muotoilla sivun oikein. Käytämme system()-funktiota kutsumaan man-komentoa ja putkitamme tuloksen toiselle sovellukselle nimeltä col, joka muotoilee tekstin ASCII-muotoon. Sieppaamme shell-komennon palautusarvon muuttujaan $return. Funktio palauttaa tulostuksensa. Voit saada aikaan samanlaisen tuloksen heittomerkkioperaattorilla. Operaattori toimii siten, että shellkomento sijoitetaan gravis-merkkien (`) sisälle. Heittomerkkien sisällä oleva komento suoritetaan ja tulos palautetaan. Voit tulostaa tuotoksen tai tallentaa sen muuttujaan. Voimme kirjoittaa edellä olevan koodin uudelleen: print "<pre>";

21. Palvelinympäristö 371 print man man col -b ; print "</pre>"; Huomaa, että meidän on tulostettava palautusarvo ulkoisella print-komennolla. Turvallisuusaukkojen tukkiminen escapeshellcmd()- funktiolla Ennen kuin tutkimme escapeshellcmd()-funktiota, tutkimme vaarat, joilta funktiolla suojaudutaan. Haluamme antaa käyttäjille mahdollisuuden kirjoittaa manuaalisivujen nimiä tekstikenttään ja tulostaa sitten löydetyt sivut selaimelle. Kyseessä on helppo tehtävä. Älä kuitenkaan asenna allaolevaa koodia (listaus 21.4); siinä on suuri turvallisuusaukko. Listaus 21.4 Manuaalisivu selaimelle man-komennolla 1: <html> 2: <head> 3: <title>listing 21.4 Calling the man command. 4: This script is not secure</title> 5: </head> 6: <body> 7: <form> 8: <input type="text" value="<?php print $manpage;?>" name="manpage"> 9: </form> 10: <pre> 11: <?php 12: if ( isset($manpage) ) 13: system( "man $manpage col -b" ); 14:?> 15: </pre> 16: </table> 17: </body> 18: </html>

372 21. Palvelinympäristö Laajennamme nyt yllä olevaa esimerkkiä hieman lisäämällä tekstikentän ja laittamalla arvon lomakkeen lähettämisen yhteydessä system()-funktiolle vietävään shell-komentoon. Turvaudumme kuitenkin UNIXjärjestelmään, jossa epärehellinen käyttäjä voisi lisätä omia komentojaan manuaalisivukenttään, jolloin hän saisi rajallisen pääsyn palvelimelle. Kuva 21.3 esittää yksinkertaisen tavan käyttää skriptiä palvelimen käsittelyyn epärehellisin keinoin. KUVA 21.3 UNIX:in mankomennon suorittaminen. Epärehellinen käyttäjä on lähettänyt arvon xxx; ls -al lomakkeen kautta. Olemme tallentaneet arvon $manpage-muuttujaan. Kun yhdistämme tekstin system()-funktion argumentiksi, tulemme suorittaneeksi komennot: "man xxx; ls -al col -b" Nuo komennot laittavat shellin noutamaan manuaalisivun komennolle www, jota ei ole olemassa. Sen jälkeen suoritetaan hakemistolistaus ja ajetaan se col-komennon läpi. Jos et näe asiassa mitään pahaa, ajattele uudelleen. Vihamielinen vierailija voi luetella kaikki luettavissa olevat hakemistot. Hän voisi lukea jopa /etc/passwd-tiedoston lisäämällä lomakekenttään tekstin: xxx; cat /etc/passwd Onneksi salasanat kryptataan tiedostoon nimeltä /etc/shadow, jota vain root voi lukea; silti kyseessä on turvallisuusaukko. Emme voi sallia tällaista. Turvallisin keino suojautua tällaiselta on estää käyttäjän suora shell-käyttö. Lisäämme hieman turvallisuutta käyttämällä escapeshellcmd()-komentoa lisäämään kenoviivat jokaisen megamerkin eteen, jonka käyttäjä saattaa lähettää. Funktio ottaa argumentikseen merkkijonon ja palauttaa muunnetun kopion. Voimme nyt muuttaa koodiamme turvallisemmaksi (listaus 21.5).

21. Palvelinympäristö 373 Listaus 21.5 Käyttäjän syöttötiedon kiertäminen escapeshellcmd()-funktiolla 1: <html> 2: <head> 3: <title>listing 21.5 Escaping user input with 4: the escapeshellcmd() function</title> 5: </head> 6: <body> 7: <form> 8: <input type="text" value="<?php print $manpage;?>" name="manpage"> 9: </form> 10: <pre> 11: <?php 12: if ( isset($manpage) ) 13: { 14: $manpage = escapeshellcmd( $manpage ); 15: system( "man $manpage col -b" ); 16: } 17:?> 18: </pre> 19: </table> 20: </body> 21: </html> Jos käyttäjä yrittää antaa komennon "xxx; cat /etc/passwd " nyt, se muunnetaan muotoon "xxx\; cat /etc/passwd ", jolloin uutta komentoa ei voida suorittaa. Itse asiassa käyttäjälle esitetään cat-komennon manuaalisivu salasanatiedoston sijaan! Vaikka voitkin parantaa turvallisuutta tällä tavoin, vältä aina sitä mahdollisuutta, että käyttäjä voi antaa shellissä suoritettavia komentoja. Voisimme parantaa vieläkin tilannetta tekemällä luettelon kaikista manuaalin komennoista, jolloin voisimme tarkistaa ensin, onko käyttäjän syöttämä komento luettelossa ja antaa komennon vasta sitten system()-funktiolle. Teemme niin seuraavassa jaksossa. Ulkoisten sovellusten ajaminen passthru()-funktiolla Funktio passthru() on samanlainen kuin system() paitsi että shell-komennon tuotosta ei puskuroida. Näin funktio sopii komennoille, jotka tuottavat binääritietoa tekstitiedon sijaan. Funktio ottaa argumentikseen shellkomennon ja valinnaisen muuttujan. Muuttuja täytetään komennon palautusarvolla. Tehkäämme nyt esimerkki. Haluamme luoda skriptin, joka näyttää kuvat ikonikoossa ja jota voidaan kutsua HTML- tai PHPsivuilta. Listaus 21.6 esittää koodin, joka paikantaa kuvan ja tulostaa tiedon selaimelle.

374 21. Palvelinympäristö Listaus 21.6 Binääritiedon tulostaminen passthru()-funktiolla 1: <?php 2: if ( isset($image) && file_exists( $image ) ) 3: { 4: header( "Content-type: image/gif" ); 5: passthru( "giftopnm $image pnmscale -xscale.5 -yscale.5 ppmtogif" ); 6: } 7: else 8: print "The image $image could not be found"; 9:?> Huomaa, että emme käyttäneet nyt escapeshellcmd()-funktiota. Sen sijaan testasimme käyttäjän syöttämän tiedon file_exists()-funktiolla. Emme vie $image-muuttujaa shellille, jos kuvaa ei ole olemassa. Voisimme tehdä skriptistä turvallisemman siten, että rajoitamme käytettäviä tiedostotyyppejä ja annamme hakemiston, josta kuvien tulisi löytyä. Funktion passthru() kutsussa suoritetaan komento, joka kutsuu kolmea sovellusta. Huomaa, että skriptisi toimiminen järjestelmässäsi edellyttää, että sinulla on nuo kolme sovellusta käytössäsi ja niiden tulee olla tiedostopolussa. Kutsumme ensiksi sovellusta nimeltä giftopnm, jolle viemme $image-muuttujan. Se lukee GIF-kuvan ja tulostaa tiedon siirrettävässä anymapmuodossa. Tämä tuotos putkitetaan pnmscale-sovellukselle, joka skaalaa kuvan 50 prosenttiin alkuperäisestä koostaan. Tämä tuotos putkitetaan vuorostaan ppmtogif-sovellukselle, joka muuntaa tiedon GIF-muotoon ja juuri tuo tieto sitten esitetään selaimella. Voimme nyt kutsua tätä skriptiä miltä tahansa Web-sivulta. <img src="listing21.6.php?image=<?php print urlencode("/path/to/image.gif")?>"> Ulkoisen CGI-skriptin kutsuminen virtual()-funktion kautta Jos muunnat täysin HTML-pohjaista sivustoa PHP-kelpoiseksi, saatat havaita, että palvelinpuolen sisällyttämiset (SSI, Server-Side Include) eivät enää toimi. Jos ajat PHP-järjstelmää Apache-moduulina, voit käyttää virtual()-funktiota kutsumaan CGI-skriptejä, esimerkiksi Perl- tai C Web -laskureita ja sisällyttää niiden tuottamat tulokset sivuillesi. Jokaisen kirjoittamasi CGI-skriptin tulee tuottaa HTTP-otsikot. Kirjoittakaamme nyt yksinkertainen Perl CGI -skripti. Jos et tunne Perliä, älä murehdi asiaa. Se vain tulostaa HTTP-otsikon ja kaikki ympäristömuuttujat, jotka ovat sen saatavilla: #!/usr/bin/perl -w print "Content-type: text/html\n\n"; foreach ( keys %ENV ){ print "$_: $ENV{$_}<br>\n"; }

21. Palvelinympäristö 375 Olettakaamme, että tämä skripti tallennetaan suoritettavaan cgi-bin-hakemiston tiedostoon nimeltä test.pl. Nyt voit kutsua sitä virtual()-funktion avulla ja sisällyttää sen tuottaman tiedon PHP-asiakirjaasi: <?php virtual("/cgi-matt/test.pl");?> Yhteenveto Tällä tunnilla opit kommunikoimaan shellin kanssa ja käyttämään ulkoisia sovelluksia sen kautta. PHP on tehokas kieli, mutta joskus on nopeampaa kutsua sovellusta kuin luoda vastaava toiminto itse. Luvun myötä opit putkittamaan tietoa komennolta toiselle popen()-funktiolla. Tämä lähestymistapa on hyödyllinen käytettäessä sovelluksia, jotka ottavat vastaa standardia syöttötietoa ja silloin kun haluat jäsennellä tietoa. Lisäksi opit käyttämään exec()- ja system()-funktioita sekä heittomerkkioperaattoria, joilla viedään komentoja shellille. Sait tietää myös vaarat, jotka liittyvät tilanteeseen, jossa käyttäjän antama tieto on mukana suoritettavassa shell-komenossa; tilannetta voitiin parantaa ecscapeshellcmd()-funktiolla, joka tarjoaa hieman suojaa väärää syöttötietoa vastaan. Opit käyttämään passthru()-funktiota, jonka avulla voidaan suorittaa shell-komento, joka tulostaa binääritietoa. Luvun lopussa sait vielä tietoa palvelinpuolen ohjelmien sisällyttämisestä skripteihin virtual()-funktion avulla. K&V K Olet maininnut sanan turvallisuus monta kertaa tällä tunnilla. Mistä saan lisää tietoa Webiin liittyvästä turvallisuudesta? V Luultavasti asiantuntevin paikka, jossa Web-turvallisuus on esillä, on Lincoln Steinin FAQ-asiakirja (Lincoln Stein on kuuluisan Perl-moduulin, CGI.pm, tekijä). Kyseinen asiakirja löytyy osoitteesta http://www.w3.org/security/faq/. K Milloin minun kannattaisi harkita ulkoisen prosessin hyödyntämistä oman skriptin luomisen sijaan? V Arviointikriteereinä kannattaa käyttää sellaisia tekijöitä kuin siirrettävyys, kehitysnopeus ja tehokkuus. Jos rakennat toiminnallisuuden skriptiisi luottamatta ulkoiseen prosessiin, skriptisi tulee suoriutua hyvin erilaisilla alustoilla tai järjestelmissä, jotka eivät sisällä käyttämääsi kolmannen osapuolen sovellusta. Yksinkertaisten tehtävien kohdalla (esimerkiksi hakemistolistauksen kohdalla) on todennäköisesti tehokkaampaa käsitellä ongelmaa koodissa, jolloin tehottomuudelta säästytään, kun toista prosessia ei tarvitse kutsua joka kerta, kun skriptisi suoritetaan.

376 21. Palvelinympäristö Toisaalta joidenkin tehtävien tekeminen PHP:llä voi olla vaikeaa tai hidasta tai itse ohjelmasta tulee hidas (esimerkiksi merkkijonon hakeminen suuresta tiedostosta). Näissä tapauksissa kannattaa tutkia työkaluja, jotka on tarkoitettu nimenomaan kyseisiin tehtäviin. Työpaja Työpaja tarjoaa joukon kertauskysymyksiä, joiden avulla voit tarkistaa, oletko ymmärtänyt materiaalin sisältöä. Yritä ymmärtää vastaukset ennen kuin jatkat seuraaviin lukuihin. Vastaukset ovat liitteessä A. Kysymyksiä 1. Millä funktiolla avaisit putken prosessiin? 2. Kuinka lukisit tietoa prosessista sen jälkeen kun olet avannut yhteyden? 3. Kuinka voit kirjoittaa tietoa prosessiin sen jälkeen kun yhteys on luotu? 4. Tulostaako exec()-funktio shell-komennon tuotoksen suoraan selaimelle? 5. Mitä system()-funktio tekee suorittamansa ulkoisen komennon tuotoksella? 6. Mitä heittomerkkioperaattori palauttaa? 7. Kuinka voit suodattaa käyttäjän syötön tehdäksesi sen hieman turvallisemmaksi ennen sen viemistä shellkomennolle? 8. Kuinka suorittaisit ulkoisen CGI-skriptin omasta skriptistäsi käsin? Toiminta 1. Luo skripti, joka käyttää UNIX:in ps-komentoa tulostamaan ajettavat prosessit selaimelle. Kun tiedät skriptin tehon, ei skriptiä tulisi antaa muiden käyttöön! 2. Tarkista ps-komennon manuaalisivulta ps-komentoon liittyvät lisäkytkimet. Lisää skriptiisi lomake, joka sallii käyttäjien valita muutamista lisäkytkimistä, joiden avulla he voivat muuttaa ps-komennon tuottamaan tulostusta. Älä lähetä mitään syöttötietoa suoraan komentoriville.