l2.php

2.3 Uppgift 2

[ Utskriftsversion av dessa uppgifter ]

 

I sin enklaste form kan ett dataprogram beskrivas på följande sätt:

  1. Vi ger programmet någon form av indata
  2. Programmet behandlar detta data
  3. Programmet visar resultatet av behandlingen

För att exemplifiera detta i PHP så skall vi göra ett lite större system: En gästbok
Detta program kommer att byggas upp del för del, och ni kan konstatera att program inte skrivs uppifrån och neråt, utan att de istället byggs på inifrån och ut genom att sätta in tilläggsfunktionalitet i flera steg.

 

OBS! Ni skall SKRIVA koden som finns. Den är lite svår att bara knycka med Copy/Paste. Om jag märker att ni bara kopierar lägger jag ut allt i pdf-format med bortkopplad copy funktionalitet. Ni kan INTE lära er NÅGONTING genom att bara kopiera...

l3.php

2.3.1 Gästbokens datafil och fillistning

OBS! Alla filer - såväl program- som datafiler - sätts i er php katalog om inte annat anges. Jag antar även att ni bläddrat genom de övriga sidorna i denna sajt, så att ni har en översikt över PHP...

Grundidén

Vi kommer att skapa ett formbaserat PHP program för en gästbok. Efter viss planering har vi kommit fram till att följande uppgifter behövs:

  1. Datum när det blev skrivet i gästboken
  2. Vem som skrivit i gästboken
  3. Elpostadressen till den som skrev
  4. En rubrik (subject) för meddelandet
  5. Själva texten i meddelandet

Dessutom finns det följande saker att beakta:

  1. Inläggen skall sorteras så att det senast skrivna kommer först och sedan de andra i omvänd ordning.
  2. För att enklast kunna sortera datum så behöver de vara i sorteringsbar ascii-form, d.v.s. i formen YYYYMMDD eller liknande med år före månad före dag före tid.
  3. Datum skall inte skrivas in i gästboken, utan de skall hanteras av systemet.
  4. För att enklast kunna sortera hela rader så sätts datum först i raden

För att lagra detta skall det användas en vanlig textfil. Det skulle även gå att använda en databas, men för tillfället duger en textfil.

 

Hur skall då denna fil se ut? Man skulle kunna tänka sig att sätta in de ovanstående uppgifterna på separata rader, men det är enklare att hantera datat om varje enskilt inlägg kommer på en rad i fil. Jämför gärna med databasers post och fält begrepp.

 

Vi börjar inte med att koda inmatningen, utan istället skapar vi en "fejkad" fil som vi jobbar vidare med.

Skapa datafilen:

Skapa en fil med namnet guestbook.txt och skriv in följande rader. Var noga med att slå <enter> efter varja rad - även den sista. Ordet <enter> skrivs inte in utan betyder att du skall trycks på enter tangenten...

2003.09.02 12:23|Mr X|mrx@some.com|Hej...|...på dej<enter>
2003.09.02 12:23|Ms Y|mry@where.com|test|testar bara<enter>

Ovastående är ett exempel på en s.k "delimited file". För att skilja fälten från varandra sätts det in ett valt tecken. Detta skulle kunna vara ett komma (comma separated values - CSV) eller tabulator (tab separated values). Jag har dock valt att sätta "|"- tecknet istället. Dels för att komma mycket väl kan förekomma i ett inlägg och dels för att tabulatorer syns lite dåligt ibland i listningar.

Skapa PHP programmet:

Det finns en praktisk liten funktion i PHP som heter file (se filerna_fil3.php). Den tar en komplett fil och sätter in resultatet i en array. Eftersom vi sett till att varje inlägg är en separat rad så är det praktiskt att kunna öppna filen i ett svep för att sedan loopa genom den. PHP har en hel del praktiska funktioner för att loopa genom arrays, t.ex. foreach (se array_cc.php) För att plocka ut de enskilda delarna av strängen använder vi explode (se array_str.php samt explode *)

Vi kommer nedan att bygga upp listningen steg för steg:

 

<?php
# öppna filen och sätt allt in i en array med namnet $innehållet
# om det inte fungerar så meddelar vi detta med Die funktionen
$innehållet = file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");

# loopa genom arrayen
foreach( $innehållet as $rad )
{
    
# plocka ut de enskilda delarna som separeras av | tecknet
    
$fälten = explode( "|", $rad );
    
$datum =  $fälten[ 0 ];
    
$vem = $fälten[ 1 ];
    
$elpost = $fälten[ 2 ];
    
$ärende = $fälten[ 3 ];
    
$texten = $fälten[ 4 ];
    
# visa bara $vem för tillfället
    
echo $vem;
}
?>
Listning 2.3.1.1 - samples/_l3.php
[Visa i separat fönster]

För att slippa använda arrays så sätter vi in värdena i ett antal variabler med namnen $datum, $vem, $elpost, $ärende och $texten. Det finns en kortare form som gör samma sak och som ser ut så här (se även array_str.php):

<?php
# öppna filen och sätt allt in i en array med namnet $innehållet
# om det inte fungerar så meddelar vi detta med Die funktionen
$innehållet = file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");

# loopa genom arrayen
foreach( $innehållet as $rad )
{
    
# plocka ut de enskilda delarna som separeras av | tecknet
    
list($datum, $vem,$elpost,$ärende,$texten) = explode( "|", $rad );
    
# visa bara $vem för tillfället
    
echo $vem;
}
?>
Listning 2.3.1.2 - samples/_l3a.php
[Visa i separat fönster]

 

Provkör programmet genom att surfa iväg till http://www.cc.puv.fi/~xxxxx/php/guestbook.php, där xxxxx är ditt användarnamn i nätverket. Tag gärna en titt på den genererade koden genom att ta <Högerklick>, View Source (i IE).

Mellananalys:

Vi borde nu ha insett följande saker:

  1. PHP har kraftfull hantering av såväl filer som arrays. I VB brukar vi kanske undvika arrays, mest eftersom de egentligen inte är så användbara, men i PHP skall vi försöka använda dem så mycket som möjligt.
  2. Variabler kan innhålla åäö, men måste börja med ett $ tecken
  3. PHP kod skall alltid omslutas med <?php .... ?>
  4. Kommentarer skrivs med hjälp av (bland annat) #
  5. För att skriva till webbsidan kan man använda echo
  6. Programsatser avslutas alltid med ;

Dessutom borde vi ha lagt märke till följande:

  1. De två raderna vi skriver kommer på samma rad på webbsidan.
  2. Det vi skapat är inte helt korrekt HTML kod, såtillvida att det fattas <html><head>... mm.

Första ändringarna i programmet:

  1. Ändra på raden:

    echo $vem;

    så att den istället blir

    echo $vem . "<br>";

    Detta gör att de två echo raderna kommer att komma på olika rader i browsern, men om du tar och tittar på den generarade html koden i browsern så är de i alla fall på samma rad i denna.

  2. Ändra samma rad till följande (och ta en titt på browserns source efteråt):

    echo $vem . "<br>\n";


  3. Vi skall även se till att det skapas giltig html kod genom att sätta in "vanlig html kod i filen. Observera att den med fördel kan sättas "utanför" php-koden:

    <html>
          <head>
            <title>En g&auml;stbok</title>
          </head>
        <body>
        <?php
        
    # öppna filen och sätt allt in i en array med namnet $innehållet
        # om det inte fungerar så meddelar vi detta med Die funktionen
        
    $innehållet = file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");
        
        
    # loopa genom arrayen
        
    foreach( $innehållet as $rad )
        {
            
    # plocka ut de enskilda delarna som separeras av | tecknet
            
    $fälten = explode( "|", $rad );
            
    $datum =  $fälten[ 0 ];
            
    $vem = $fälten[ 1 ];
            
    $elpost = $fälten[ 2 ];
            
    $ärende = $fälten[ 3 ];
            
    $texten = $fälten[ 4 ];
            
    # visa bara $vem för tillfället
            
    echo $vem . "<br>\n";
        }
        
    ?>
        </body>
    </html>
    Listning 2.3.1.3 - samples/_l3b.php
    [Visa i separat fönster]


    OBS! Jag kommer i fortsättningen att lämna bort all icke nödvändig html kod för att spara utrymme. Det är självklart att du skall se till att php skapar korrekta html sidor.

Mer komplett visning av gästboken

För att komma vidare måste vi sätta ut mer av de uppgifter som finns i gästboksfilen, samt även formatera dessa. För formateringen kommer det att användas html-tabeller så om du inte är förtrigen med dess så bör du ta en snabb titt på vad <table>, <tr> och <td> har för betydelse i vanlig html.

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <?php
    
# öppna filen och sätt allt in i en array med namnet $innehållet
    # om det inte fungerar så meddelar vi detta med Die funktionen
    
$innehållet = file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");
    
    
# börja en tabell - detta skall ske före loopen
    # sätt in radbyten \n för att ge mer lättläst kod om du
    # tittar på source...
    # observera änven att man inte kan skriva border="1" eftersom
    # "-tecknet skulle avsluta strängen. Man måste skriva \" för att få
    # ett " tecken innuti en teckensträng
    
    
echo "<table border=\"1\">\n";    
    

    # loopa genom arrayen
    
foreach( $innehållet as $rad )
    {
        
# plocka ut de enskilda delarna som separeras av | tecknet
        
$fälten = explode( "|", $rad );
        
$datum =  $fälten[ 0 ];
        
$vem = $fälten[ 1 ];
        
$elpost = $fälten[ 2 ];
        
$ärende = $fälten[ 3 ];
        
$texten = $fälten[ 4 ];
        
# nedan är nytt/ändrat
        # en rad för datum
        
        
echo "<tr><td>" . $datum . "</td></tr>\n";
        
# och fortsätt med resten
        
echo "<tr><td>" . $vem . "</td></tr>\n";
        echo
"<tr><td>" . $elpost . "</td></tr>\n";
        echo
"<tr><td>" . $ärende . "</td></tr>\n";
        echo
"<tr><td>" . $texten . "</td></tr>\n";        
        

    
}
    
# avsluta tabellen - detta skall ske efter loopen
    
    
echo "</table>\n";
    

    
?>
    </body>
</html>
Listning 2.3.1.4 - samples/_l3c.php
[Visa i separat fönster]

 

Listningen ser inte så vacker ut men det är ditt problem att få den snyggare. Kom bara ihåg att varje gång du vill få " i en teckensträng så måste du skriva \", t.ex för att få <td colspan="2"> så måste du skriva echo "<td colspan=\"2\">";

En vidareutveckling

Tag en titt på nedanstående kod och ändra i ditt program det som visas som överstruket till det som visas med fetstil. Tag sedan en ordentlig funderare på hur citationstecken mm. egentligen kommer in i den genererade koden...

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <?php
    $innehållet
= file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");
    
    echo
"<table border=\"1\">\n";    
    foreach(
$innehållet as $rad )
    {
        
$fälten = explode( "|", $rad );
        
$datum =  $fälten[ 0 ];
        
$vem = $fälten[ 1 ];
        
$elpost = $fälten[ 2 ];
        
$ärende = $fälten[ 3 ];
        
$texten = $fälten[ 4 ];
        echo
"<tr><td>" . $datum . "</td></tr>\n";
        echo
"<tr><td>" . $vem . "</td></tr>\n";
        
        
echo "<tr><td>" . $elpost . "</td></tr>\n";
        
        
echo "<tr><td><a href=\"mailto:" . $elpost . "\">";
        echo
$elpost . "</a></td></tr>\n";
        

        
echo "<tr><td>" . $ärende . "</td></tr>\n";
        echo
"<tr><td>" . $texten . "</td></tr>\n";        
    }
    echo
"</table>\n";
    
?>
    </body>
</html>
Listning 2.3.1.5 - samples/_l3d.php
[Visa i separat fönster]

Du bör nu:

  1. Fundera över om du förstår den kod vi hitintills har. Om inte, bör du kontrollera från övriga sidor på denna site, och/eller ta en titt på nätet (förslagsvis på php:s hemsida) efter mer information om de enskilda programkoncept som framgår ur koden.
  2. Du får även "snygga till" den tabell som används för att visa gästboken. Ändra dock inte variabelnamnen.
  3. Du kan även fundera lite över lämpligheten att sätta ut mailto: länkar på en webbsida...
l4.php

2.3.2 Datumformat och sortering

Datum skrivs inte ut som vi vill ha det i Finland. Som datum är skapat är det dock enkelt att plocka ut de enskilda delarna. Året är alltid de fyra första tecknen, månad börjar alltid vid postion fem och är två tecken osv. För detta kan vi använda php-funktionen substr (se strings_van.php#substr). Vill vi att eventuella 0-utfyllnader skall tas bort kan vi omvandla delsträngen till ett heltal med t.ex. casting (se variabler.php)

 

Även sorteringen är enkel, eftersom det finns färdiga funktioner för arraysortering i php (se array_sort.php)

 

Se nedanstående kod:

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <?php
    $innehållet
= file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");
    

    # sortera i omvänd ordning
    
arsort($innehållet);
    

    
echo "<table border=\"1\">\n";    
    foreach(
$innehållet as $rad )
    {
        
$fälten = explode( "|", $rad );
        
$datum =  $fälten[ 0 ];
        
$vem = $fälten[ 1 ];
        
$elpost = $fälten[ 2 ];
        
$ärende = $fälten[ 3 ];
        
$texten = $fälten[ 4 ];
        

        # plocka ut de olika delarna av datumet och plocka
        # ihop dem igen i rätt ordning
        
$datum = substr($datum, 8, 2) . "." .
                     (int)
substr($datum, 5, 2) . "." .
                     (int)
substr($datum, 0, 4) . " " .
                    
substr($datum, 11);        
        

        
echo "<tr><td>" . $datum . "</td></tr>\n";
        echo
"<tr><td>" . $vem . "</td></tr>\n";
        echo
"<tr><td><a href=\"mailto:" . $elpost . "\">";
        echo
$elpost . "</a></td></tr>\n";
        echo
"<tr><td>" . $ärende . "</td></tr>\n";
        echo
"<tr><td>" . $texten . "</td></tr>\n";        
    }
    echo
"</table>\n";
    
?>
    </body>
</html>
Listning 2.3.2.1 - samples/_l3e.php
[Visa i separat fönster]

 

l5.php

2.3.3 En html form

Vi sätter in en helt vanlig html-form i vårt program. Observera att formen sätts "utanför" php-koden och att php-koden skall vara oförändrad från tidigare steg. För mer om formar se forms.php. Man kan med fördel använda t.ex. Dreamweaver för att konstruera formen, eftersom denna inte skrivs i PHP.

 

Du bör framför allt observera name= som används för alla komponenter i formen. Provkör gärna koden nedan genoma att klicka på länken under koden. Skriv in något i textrutorna och klicka sedan på "Skriv" knappen. Tag en titt på hur adressradens URL ändras.

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <form>
        <table border="1">
        <tr><td>Namn:</td><td>
            <input type="text" name="vem">
        </td></tr>
        <tr><td>Elpost:</td><td>
            <input type="text" name="elpost">
        </td></tr>
        <tr><td>Ärende:</td><td>
            <input type="text" name="arende">
        </td></tr>
        <tr><td>Text:</td>
        <td>
            <textarea name="texten" rows="5" cols="40"></textarea>
        </td></tr>
        <tr><td>&nbsp;</td><td>
            <input type="submit" name="knapp" value="    Skriv    ">
        </td></tr>
        </table>
    </form>
    <?php
    
# all PHP kod som tidigare
    # ...
    
?>
    </body>
</html>
Listning 2.3.3.1 - samples/_l3f.php
[Visa i separat fönster]

l6.php

2.3.4 Hantering av formdatat med PHP

För att kunna hantera det data som blev sänt av formen behöver vi göra ett tillägg i php-koden

 

Se isset.php, _request.php samt datum.php för mer information.

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <form>
        <table border="1">
        <tr><td>Namn:</td><td>
            <input type="text" name="vem">
        </td></tr>
        <tr><td>Elpost:</td><td>
            <input type="text" name="elpost">
        </td></tr>
        <tr><td>Ärende:</td><td>
            <input type="text" name="arende">
        </td></tr>
        <tr><td>Text:</td>
        <td>
            <textarea name="texten" rows="5" cols="40"></textarea>
        </td></tr>
        <tr><td>&nbsp;</td><td>
            <input type="submit" name="knapp" value="    Skriv    ">
        </td></tr>
        </table>
    </form>
    <?php
    

    # kontrollera om det fanns "knapp=" i URL raden
    
if ( isset( $_REQUEST[ "knapp" ] ) )    
    {
        
# tag vem= värdet från URL
        
$vem = $_REQUEST[ "vem" ];
        
        
# tag elpost= värdet från URL    
        
$elpost = $_REQUEST[ "elpost" ];
        
        
# tag arende= värdet från URL            
        # observera att man helst inte skall använda
        # åäö i URL sammanhang
        # i PHP går det däremot bra med åäö
        
$ärende = $_REQUEST[ "arende" ];
        
        
# tag texten= värdet från URL            
        
$texten = $_REQUEST[ "texten" ];

        
# tag datum från systemet och formatera detta korrekt
        
$datum = date("Y.m.d H:i");
        
        
# skarva ihop en textsträng som skall kunna skrivas till filen
        
$allt = $datum . "|" . $vem . "|" . $elpost . "|" .
                
$ärende . "|" . $texten ;
                
        
# för tillfället visar vi den bara på sidan och skriver inte
        # till någon fil
        
echo "Du klickade på Skriv och
                följande kommer att sättas i filen<br><pre>"
;
        echo
$allt;
        echo
"<pre>";
    }
    

    # all PHP kod som tidigare
    # ...
    
?>
    </body>
</html>
Listning 2.3.4.1 - samples/_l3g.php
[Visa i separat fönster]

Prova programmet genom att skriva in olika saker i formen...

l7.php

2.3.5 Problem...

Det finns några problem med koden som den är. Prova genom att skriva in följande i Text: textarean på sidan som finns under denna länk:

  1. hej "kalle"
  2. Nu skall jag jäklas <textarea rows=1000>Hi hi</textarea>De va kul
  3. <a href=http://www.en.mycket.hemsk.porrsajt.com>oskyldig länk?</a>
  4. <font face=arial color=red size=7>Im BIG</font>
  5. En rad<enter>
    en till rad<enter>
    och en till
  6. En massa streck ||||||||||

Vi ser tydligt att måste beakta två saker i texten för att kunna sätta in detta i vår fil (som skall ha en rad per inlägg i gästboken):

  1. Radbyten måste beaktas och kanske bytas ut till <br>
  2. Vi kan inte godkänna html kod i texten - förr eller senare kommer det en lustigkurre och skriver t.ex. textarea exemplet ovan...
  3. Eftersom vår fil använder | för att avdela mellan fälten måste dessa tas bort om någon skriver in dem i en textbox.
  4. Eftersom PHP ändrar " till \" måste vi ändra den tillbaka...

Nedan är koden som beaktar detta. Tag eventuellt en titt på strings_conv.php, strings_van.php, funktioner.php samt syntax.php för mer information om de använda funktionerna.

 

Eftersom det är flera strängar som behöver beaktas/modifieras är det enklast att skapa en funktion som sköter om detta.

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <form>
        <table border="1">
        <tr><td>Namn:</td><td>
            <input type="text" name="vem">
        </td></tr>
        <tr><td>Elpost:</td><td>
            <input type="text" name="elpost">
        </td></tr>
        <tr><td>Ärende:</td><td>
            <input type="text" name="arende">
        </td></tr>
        <tr><td>Text:</td>
        <td>
            <textarea name="texten" rows="5" cols="40"></textarea>
        </td></tr>
        <tr><td>&nbsp;</td><td>
            <input type="submit" name="knapp" value="    Skriv    ">
        </td></tr>
        </table>
    </form>
    <?php
    

    # funktion som "städar upp" texen så att den skall gå
    # att sätta in i filen
    
function beakta_alla_dumheter( $text )
    {
        
# tag bort alla html tags i texten
        
$text = strip_tags( $text );
        
# tag bort alla html tags i texten
        
$text = strip_tags( $text );
        
        
# sätt in <br> tags där det finns <enter> (CRLF)
        
$text = nl2br( $text );

        
# Radbyten hanteras lite olika i olika miljöer
        # i Unix sätts det in en LF (ascii 13) som i PHP
        # betecknas med \n
        # medan Windows maskiner sätter in CRLF (ascii 10 + ascii 13)
        # som i PHP betecknas med \r\n
        # för säkerhets skull tar vi bort bägge
        
        # tag bort eventuella \r ( CR )
        
$text = str_replace( "\r", "", $text  );
        
# tag bort eventuella \n ( LF )
        
$text = str_replace( "\n", "", $text );
        
        
# byt ut \" till " - jo det skall vara "\\\""
        
$text = str_replace( "\\\"", "\"", $text );

        
# tag bort eventuella | tecken
        
$text = str_replace( "|", "", $text );
        
        
# låt funktionen returnera den modifierade texten
        
return $text;
    }
    

    
if ( isset( $_REQUEST[ "knapp" ] ) )    
    {
        
$vem = $_REQUEST[ "vem" ];
        
$elpost = $_REQUEST[ "elpost" ];
        
$ärende = $_REQUEST[ "arende" ];
        
$texten = $_REQUEST[ "texten" ];
        
$datum = date("Y.m.d H:i");
        

        
$vem        = beakta_alla_dumheter( $vem );
        
$ärende     = beakta_alla_dumheter( $ärende );
        
$elpost     = beakta_alla_dumheter( $elpost );
        
$texten     = beakta_alla_dumheter( $texten );
        


        
$allt = $datum . "|" . $vem . "|" . $elpost . "|" .
                
$ärende . "|" . $texten ;
        

        # ändrat lite på echo för att visa tydligare vad som skett
        
echo "Du klickade på Skriv och
                följande kommer att sättas i filen<br>"
;
        echo
htmlentities ($allt);
        

    
}
    

    # all PHP kod som tidigare
    # ...
    
?>
    </body>
</html>
Listning 2.3.5.1 - samples/_l3i.php
[Visa i separat fönster]

OBS! För tillfället bryr vi oss inte om att det kan lämnas tomt i alla textboxar - valideringen kommer senare...

l8.php

2.3.6 Skrivning till filen

Det är förhållandevis enkelt att läsa filer. Hela Internet går ju ut på att läsa filer och visa dessa. Att skriva är dock lite mer komplicerat.

 

Kopiera all kod som fiinns i rutan nedan och sätt in i en ny fil som du kallar filtest.php. Prova detta program genom att surfa till detta program på din hemsideskatalog.

 

<?php     
    $teststräng
= "en liten teststräng";
    
# Öppna en fil för skrivning      
    # skapa den vid behov
    
$filen = fopen ( "testa.txt", "w+" );

     
    
# gick det?
    
if ( $filen )  
    {
        
# lås filen så att andra kan läsa men inte skriva
        
flock( $filen, 1 );
        
# skriv till filen
        
fputs ( $filen, $teststräng );
        
# tag bort låsningen
        
flock( $filen, 3 );  
        
# stäng filen
        
fclose ( $filen );
        echo
"Har skrivit till filen";
    }
    else
    {
        echo
"Det sket sig!";
    }
    
?>
Listning 2.3.6.1 - samples/tt2.php
[Visa i separat fönster]

 

Om detta program fungerar är allt frid och fröjd, men troligtvis får du följande resultat istället (... kommer att ersättas av din hemkatalogs path):


Warning: fopen("testa.txt", "w+") - Permission denied in

...\tt2.php on line 5
Det sket sig!

 

Om du fick ett felmeddelande i stil med ovanstående beror detta på att php-programmet inte har rätt att skriva till denna fil. Gör i så fall följande:

(Bägge operativsystemen kräver således att filen finns för att man skall kunna ändra på dess rättigheter. En bättre idé kan vara att sätta alla filer som skall kunna ändras till en underkatalog, och därefter se till att hela katalogen har modifieringsrättigheter.)

 

Efter att ha gjort ovanstående ändringar i filskyddet för testa.txt kan du prova filtest.php igen. Förhoppningsvis fungerar det nu.

 

Du kan även prova följande ändringar. Prova programmet flera gånger genom att klicka på refresh i din browser. Tag sedan en titt på vad filen testa.txt innehåller.

 

<?php     
    $teststräng
= "en liten teststräng";
    
# Öppna en fil för skrivning      
    # skapa den vid behov
    
    
$filen = fopen ( "testa.txt", "a");

     
    
# gick det?
    
if ( $filen )  
    {
        
# lås filen så att andra kan läsa men inte skriva
        
flock( $filen, 1 );
        
# skriv till filen
        
fputs ( $filen, $teststräng . "\r\n");
        
# tag bort låsningen
        
flock( $filen, 3 );  
        
# stäng filen
        
fclose ( $filen );
        echo
"Har skrivit till filen";
    }
    else
    {
        echo
"Det sket sig!";
    }
    
?>
Listning 2.3.6.2 - samples/tt3.php
[Visa i separat fönster]

Modifiera din gästboksfil

Se till att guestbook.txt har skrivrättigheter satt på samma sätt som du satte skrivrättigheter för filen testa.txt. Vill du veta vad 766 egentligen betyder så ta en titt på sidan filerna_fil.php. Dessutom kan det vara skäl att se hur fopen fungerar på sidan filerna_fil3.php

 

Modifiera din guestbook.php

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <form>
        <table border="1">
        <tr><td>Namn:</td><td>
            <input type="text" name="vem">
        </td></tr>
        <tr><td>Elpost:</td><td>
            <input type="text" name="elpost">
        </td></tr>
        <tr><td>Ärende:</td><td>
            <input type="text" name="arende">
        </td></tr>
        <tr><td>Text:</td>
        <td>
            <textarea name="texten" rows="5" cols="40"></textarea>
        </td></tr>
        <tr><td>&nbsp;</td><td>
            <input type="submit" name="knapp" value="    Skriv    ">
        </td></tr>
        </table>
    </form>
    <?php
    
function beakta_alla_dumheter( $text )
    {
        
$text = strip_tags( $text );
        
$text = strip_tags( $text );
        
$text = nl2br( $text );
        
$text = str_replace( "\r", "", $text  );
        
$text = str_replace( "\n", "", $text );
        
$text = str_replace( "\\\"", "\"", $text );
        
$text = str_replace( "|", "", $text );
        return
$text;
    }
    if ( isset(
$_REQUEST[ "knapp" ] ) )    
    {
        
$vem = $_REQUEST[ "vem" ];
        
$elpost = $_REQUEST[ "elpost" ];
        
$ärende = $_REQUEST[ "arende" ];
        
$texten = $_REQUEST[ "texten" ];
        
$datum = date("Y.m.d H:i");
        
$vem        = beakta_alla_dumheter( $vem );
        
$ärende     = beakta_alla_dumheter( $ärende );
        
$elpost     = beakta_alla_dumheter( $elpost );
        
$texten     = beakta_alla_dumheter( $texten );
        
$allt = $datum . "|" . $vem . "|" . $elpost . "|" .
                
$ärende . "|" . $texten ;

        
# ändrat lite på echo för att visa tydligare vad som skett
        echo "Du klickade på Skriv och
                följande kommer att sättas i filen<br>";
        echo htmlentities ($allt);

        
        # öppna guestbook.txt för "append" = tillägg
        
$filen = fopen ( "guestbook.txt", "a");  
        
# gick det?
        
if ( $filen )   
        {  
            
# lås filen så att andra kan läsa men inte skriva
            
flock( $filen, 1 );  
            
# skriv till filen \n är för att notepad skall
            
fputs ( $filen, $allt . "\n");  
            
# tag bort låsningen
            
flock( $filen, 3 );   
            
# stäng filen
            
fclose ( $filen );
        }
        

    
}

    
# all PHP kod som tidigare
    # ...
    
?>
    </body>
</html>
Listning 2.3.6.3 - samples/_l3j.php
[Visa i separat fönster]

l9.php

2.3.7 Nästan klar, men...

Förhoppningsvis har du nu en hyfsat fungerande gästbok.

 

Det finns dock två allvarliga buggar + ett litet problem:

  1. Om man tar Refresh på sidan efter att ha skrivit i gästboken så kommer det stt skrivas samma sak på nytt.
  2. Man kan ju faktiskt lämna tomt i alla fält.
  3. Koden börjar bli lite komplicerad - mest eftersom den innehåller såväl html som php kod. Jobbar vi vidare på så sätt blir allt en hemsk soppa.
Det är den sista vi skall börja med...

Dela upp html och kod

Tag en kopia av din fil guestbook.php och kalla kopian för guestcode.php (den skall finnas i samma katalog som guestbook.php och guestbook.txt)

 

Modifiera sedan guestcode.php så att allt som inte finns innanför <?php och ?> tas bort. Se även till att <?php kommer direkt som första rad / tecken i filen:

<?php
    
function beakta_alla_dumheter( $text )
    {
        
$text = strip_tags( $text );
        
$text = strip_tags( $text );
        
$text = nl2br( $text );
        
$text = str_replace( "\r", "", $text  );
        
$text = str_replace( "\n", "", $text );
        
$text = str_replace( "\\\"", "\"", $text );
        
$text = str_replace( "|", "", $text );
        return
$text;
    }
    if ( isset(
$_REQUEST[ "knapp" ] ) )    
    {
        
$vem = $_REQUEST[ "vem" ];
        
$elpost = $_REQUEST[ "elpost" ];
        
$ärende = $_REQUEST[ "arende" ];
        
$texten = $_REQUEST[ "texten" ];
        
$datum = date("Y.m.d H:i:s");
        
$vem        = beakta_alla_dumheter( $vem );
        
$ärende     = beakta_alla_dumheter( $ärende );
        
$elpost     = beakta_alla_dumheter( $elpost );
        
$texten     = beakta_alla_dumheter( $texten );
        
$allt = $datum . "|" . $vem . "|" . $elpost . "|" .
                
$ärende . "|" . $texten ;
        
$filen = fopen ( "guestbook.txt", "a");  
        if (
$filen )   
        {  
            
flock( $filen, 1 );  
            
fputs ( $filen, $allt . "\n");  
            
flock( $filen, 3 );   
            
fclose ( $filen );
        }
    }
    
$innehållet = file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");
    
arsort($innehållet);
    echo
"<table border=\"1\">\n";     
    foreach(
$innehållet as $rad )
    {
        
$fälten = explode( "|", $rad );
        
$datum =  $fälten[ 0 ];
        
$vem = $fälten[ 1 ];
        
$elpost = $fälten[ 2 ];
        
$ärende = $fälten[ 3 ];
        
$texten = $fälten[ 4 ];
        
$datum = substr($datum, 8, 2) . "." .
                     (int)
substr($datum, 5, 2) . "." .
                     (int)
substr($datum, 0, 4) . " " .
                     
substr($datum, 11);         
         
        echo
"<tr><td>" . $datum . "</td></tr>\n";
        echo
"<tr><td>" . $vem . "</td></tr>\n";
        echo
"<tr><td><a href=\"mailto:" . $elpost . "\">";
        echo
$elpost . "</a></td></tr>\n";
        echo
"<tr><td>" . $ärende . "</td></tr>\n";
        echo
"<tr><td>" . $texten . "</td></tr>\n";         
    }
    echo
"</table>\n";
?>
Listning 2.3.7.1 - samples/guestcode.php
[Visa i separat fönster]

Modifiera sedan gustbook.php så att all php-kod tas bort:

<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <form>
        <table border="1">
        <tr><td>Namn:</td><td>
            <input type="text" name="vem">
        </td></tr>
        <tr><td>Elpost:</td><td>
            <input type="text" name="elpost">
        </td></tr>
        <tr><td>Ärende:</td><td>
            <input type="text" name="arende">
        </td></tr>
        <tr><td>Text:</td>
        <td>
            <textarea name="texten" rows="5" cols="40"></textarea>
        </td></tr>
        <tr><td>&nbsp;</td><td>
            <input type="submit" name="knapp" value="    Skriv    ">
        </td></tr>
        </table>
    </form>
    
    </body>
</html>
Listning 2.3.7.2 - samples/guestbook.php
[Visa i separat fönster]

Du har nu två php-filer: en med alla php kod och en med all html kod.

 

Ändra sedan guestcode.php så att gästbokslistningen blir till en funktion:

<?php
    
function beakta_alla_dumheter( $text )
    {
        
$text = strip_tags( $text );
        
$text = strip_tags( $text );
        
$text = nl2br( $text );
        
$text = str_replace( "\r", "", $text  );
        
$text = str_replace( "\n", "", $text );
        
$text = str_replace( "\\\"", "\"", $text );
        
$text = str_replace( "|", "", $text );
        return
$text;
    }
    if ( isset(
$_REQUEST[ "knapp" ] ) )    
    {
        
$vem = $_REQUEST[ "vem" ];
        
$elpost = $_REQUEST[ "elpost" ];
        
$ärende = $_REQUEST[ "arende" ];
        
$texten = $_REQUEST[ "texten" ];
        
$datum = date("Y.m.d H:i:s");
        
$vem        = beakta_alla_dumheter( $vem );
        
$ärende     = beakta_alla_dumheter( $ärende );
        
$elpost     = beakta_alla_dumheter( $elpost );
        
$texten     = beakta_alla_dumheter( $texten );
        
$allt = $datum . "|" . $vem . "|" . $elpost . "|" .
                
$ärende . "|" . $texten ;
        
$filen = fopen ( "guestbook.txt", "a");  
        if (
$filen )   
        {  
            
flock( $filen, 1 );  
            
fputs ( $filen, $allt . "\n");  
            
flock( $filen, 3 );   
            
fclose ( $filen );
        }
    }

    
function visa_gästboken()
    {

        
$innehållet = file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");
        
arsort($innehållet);
        echo
"<table border=\"1\">\n";     
        foreach(
$innehållet as $rad )
        {
            
$fälten = explode( "|", $rad );
            
$datum =  $fälten[ 0 ];
            
$vem = $fälten[ 1 ];
            
$elpost = $fälten[ 2 ];
            
$ärende = $fälten[ 3 ];
            
$texten = $fälten[ 4 ];
            
$datum = substr($datum, 8, 2) . "." .
                         (int)
substr($datum, 5, 2) . "." .
                         (int)
substr($datum, 0, 4) . " " .
                        
substr($datum, 11);         
            
            echo
"<tr><td>" . $datum . "</td></tr>\n";
            echo
"<tr><td>" . $vem . "</td></tr>\n";
            echo
"<tr><td><a href=\"mailto:" . $elpost . "\">";
            echo
$elpost . "</a></td></tr>\n";
            echo
"<tr><td>" . $ärende . "</td></tr>\n";
            echo
"<tr><td>" . $texten . "</td></tr>\n";         
        }
        echo
"</table>\n";

    
}

?>
Listning 2.3.7.3 - samples/guestcode2.php
[Visa i separat fönster]

Ändra sedan guestbook.php på följande sätt:

<?php

include_once("guestcode.php");
# säkrare version kan vara:
# include_once( dirname(__FILE__) . "/guestcode.php");

?>
<html>
      <head>
        <title>En g&auml;stbok</title>
      </head>
    <body>
    <form>
        <table border="1">
        <tr><td>Namn:</td><td>
            <input type="text" name="vem">
        </td></tr>
        <tr><td>Elpost:</td><td>
            <input type="text" name="elpost">
        </td></tr>
        <tr><td>Ärende:</td><td>
            <input type="text" name="arende">
        </td></tr>
        <tr><td>Text:</td>
        <td>
            <textarea name="texten" rows="5" cols="40"></textarea>
        </td></tr>
        <tr><td>&nbsp;</td><td>
            <input type="submit" name="knapp" value="    Skriv    ">
        </td></tr>
        </table>
    </form>
    <?php
    
visa_gästboken();
    
?>
    </body>
</html>
Listning 2.3.7.4 - samples/guestbook2.php
[Visa i separat fönster]

 

Dess ändringar gör php-koden mer modulär och html-koden blir enklare att editera i en vanlig html-editor. Dessutom kan man nu dela upp projektet så att en person skriver php och en annan skriver html; en ack så viktig finess...

 

l10.php

2.3.8 Refresh problematiken

Problemet är ju att URL i adressfältet är guestbook.php?vem=aa&...

efter att vi skrivit i gästboken, och om vi laddar om sidan är det ju denna url som laddas.

Vi borde således "tömma" adressen från alla parametrar efter att vi skrivit till filen. Det går dock inte att tömma dessa i efterskott. Det är däremot helt möjligt att ladda sidan på nytt, man denna gång utan parametrar. Detta görs med några rader på lämpligt ställe, se nedan:

 

<?php
    
function beakta_alla_dumheter( $text )
    {
        
$text = strip_tags( $text );
        
$text = strip_tags( $text );
        
$text = nl2br( $text );
        
$text = str_replace( "\r", "", $text  );
        
$text = str_replace( "\n", "", $text );
        
$text = str_replace( "\\\"", "\"", $text );
        
$text = str_replace( "|", "", $text );
        return
$text;
    }
    if ( isset(
$_REQUEST[ "knapp" ] ) )
    {
        
$vem = $_REQUEST[ "vem" ];
        
$elpost = $_REQUEST[ "elpost" ];
        
$ärende = $_REQUEST[ "arende" ];
        
$texten = $_REQUEST[ "texten" ];
        
$datum = date("Y.m.d H:i:s");
        
$vem        = beakta_alla_dumheter( $vem );
        
$ärende     = beakta_alla_dumheter( $ärende );
        
$elpost     = beakta_alla_dumheter( $elpost );
        
$texten     = beakta_alla_dumheter( $texten );
        
$allt = $datum . "|" . $vem . "|" . $elpost . "|" .
                
$ärende . "|" . $texten ;
        
$filen = fopen ( "guestbook.txt", "a");
        if (
$filen )
        {
            
flock( $filen, 1 );
            
fputs ( $filen, $allt . "\n");
            
flock( $filen, 3 );
            
fclose ( $filen );
        }

        # ladda sidan på nytt - men utan några ULR parametrar
        # du får INTE skriva något till sidan innan du sätter
        # header
        # OBS! Stora L i Location och EXAKT ett
        # mellanslag efter :
        
header("Location: guestbook.php");
        exit;

    
}

    function
visa_gästboken()
    {
        
$innehållet = file ( "guestbook.txt" ) Or Die("Kunde inte öppna filen");
        
arsort($innehållet);
        echo
"<table border=\"1\">\n";
        foreach(
$innehållet as $rad )
        {
            
$fälten = explode( "|", $rad );
            
$datum =  $fälten[ 0 ];
            
$vem = $fälten[ 1 ];
            
$elpost = $fälten[ 2 ];
            
$ärende = $fälten[ 3 ];
            
$texten = $fälten[ 4 ];
            
$datum = substr($datum, 8, 2) . "." .
                         (int)
substr($datum, 5, 2) . "." .
                         (int)
substr($datum, 0, 4) . " " .
                        
substr($datum, 11);

            echo
"<tr><td>" . $datum . "</td></tr>\n";
            echo
"<tr><td>" . $vem . "</td></tr>\n";
            echo
"<tr><td><a href=\"mailto:" . $elpost . "\">";
            echo
$elpost . "</a></td></tr>\n";
            echo
"<tr><td>" . $ärende . "</td></tr>\n";
            echo
"<tr><td>" . $texten . "</td></tr>\n";
        }
        echo
"</table>\n";
    }
?>
Listning 2.3.8.1 - samples/guestcode3.php
[Visa i separat fönster]

 

Vad gör vi egentligen?

Location modifierar headern på sidan. Tag en titt på följande länk (location.php) där jag visar allt - inklusive headern - som sänds från servern för två sidor, den ena är en sida som finns, medan den andra är en sida som "redirectar" till en annan sida. Observera att Location: är satt på den andra sidan.

När browsern stöter på Location i headern så kommer den att ladda den url som där anges, utan att fortsätta med sidan. Det är detta vi simulerar genom att sätta Header("Location: guestbook.php")

 

 

l11.php

2.3.9 Validering

Den enklaste formen av validering är att låta JavaScript sköta om detta redan på klienten. Se även Uppgift 1.5 (ep1.php)

<?php
include_once("guestcode3.php");
?>
<html>
      <head>
        <title>En g&auml;stbok</title>

        <script>
        <!--
        function kolla()
        {
            // kontrollera om det står något i formen med namnet
            // myform och textboxen vem
            if (document.myform.vem.value.length == 0)
            {
                alert("Du måste ange namn.");
                return false;
            }
            if (document.myform.elpost.value.length == 0)
            {
                alert("Du måste ange elpost.");
                return false;
            }
            if (document.myform.arende.value.length == 0)
            {
                alert("Du måste ange ärende.");
                return false;
            }
            if (document.myform.texten.value.length == 0)
            {
                alert("Du måste ange ärende.");
                return false;
            }
        }
        //-->
        </script>

      </head>
    <body>
    <form name="myform" onsubmit="return kolla();">
        <table border="1">
        <tr><td>Namn:</td><td>
            <input type="text" name="vem">
        </td></tr>
        <tr><td>Elpost:</td><td>
            <input type="text" name="elpost">
        </td></tr>
        <tr><td>Ärende:</td><td>
            <input type="text" name="arende">
        </td></tr>
        <tr><td>Text:</td>
        <td>
            <textarea name="texten" rows="5" cols="40"></textarea>
        </td></tr>
        <tr><td>&nbsp;</td><td>
            <input type="submit" name="knapp" value="    Skriv    ">
        </td></tr>
        </table>
    </form>
    <?php
    visa_gästboken
();
    
?>
    </body>
</html>
Listning 2.3.9.1 - samples/guestbook4.php
[Visa i separat fönster]

 

 

 

l12.php

2.3.10 Din uppgift

Jag antar att du nu har gått igenom alla steg, och dessutom försökt lista ut vad alla delar av programmet gör - har du inte eller vet du inte går du först igenom alla tidigare delar en gång till.

 

Jag vill sedan att du skall göra följande:

  1. Sekunder
    Gästbokens sortering fungerar inte för inlägg som skett samma minut. Ändra koden där det skrivs till textfilen så att även sekunder skrivs in i filen. Som det är nu är det ju bara timmar och minuter.

  2. Sortering
    Ändra sortering så att inläggen listas med de äldsta först och nyare senare.

  3. Numrering
    Ändra visningen av gästboksinlägg så att varje inlägg numreras. Numreringen sker så att första som visas får nummer 1, den andra får nummer 2 o.s.v.
    Tips: En klassisk ackumulerande variabel i loopen gör säkert susen...

  4. Snygga till
    Snygga till sidan. Formen (guestbook.php) går att snygga till i t.ex. Dremweaver, medan koden för listningen kräver kunskap i html. Observera hur html-attribut skrivs in i textsträngar...

  5. Textfilen
    När vi öppnar en fil för append, så skapas den om den inte finns. Problemet med nuvarande kod är att filen först måste skapas, så att vi kan ge den rätta filsäkerhetsinställningar. En lösning är att skapa en data katalog under vår php katalog. Om vi ger data katalogen skrivrättigheter kommer alla filer som skapas där även att ha skrivrättigheter.
    Skapa data katalogen, ge den skrivrättigheter och modifiera sedan koden så att guestbook.txt antas finnas i denna katalog. Prova koden genom att inte ha en färdig guestbook.txt.

    OBS! i en Unix miljö funkar det oftast bäst om vi anger att data är en underkatalog till nuvarande genom att skriva "./data/gustbook.txt" och inte "data/gustbook.txt".
    OBS2! Även om vi använder Windows så fungerar / i PHP - använd aldrig \ som i t.ex. "data\guestbook.txt" utan använd alltid sk. "forward slash" som i Unix (/).

  6. Och om du vill...
    Extra uppgift. Ej obligatorisk, men ger charmpoäng ;-)
    På sidan http://www.bet.puv.fi/anders.enges/enges/ finns den enda gästbok jag någonsin gjort. Det som skiljer denna från vår är att i min gästbok kan man även göra hemliga inlägg. Ändra på koden så att även hemliga inlägg kan göras. Detta kräver ändring i såväl form, kod som filstruktur för gästboksfilen.

 

 


© anders enges, 2003