Eksamen, forår 2001

for Database-baseret Web-publicering, forår 2001

af Niels Hallenberg - PHP-modificeret af Mejner Olesen


Introduktion

I dette eksamenssæt skal du implementere dele af en webbaseret nyhedsliste. Nyhedslisten ligner meget den, der anvendes på IT-højskolen i København (IT-C).

Ideen med nyhedslisten er, at personer, som er tilmeldt listen, automatisk får tilsendt emails, når IT-C annoncerer nyheder. Dette kan eksempelvis være stillingsopslag, nye uddannelser og Buzz Talks. Når personer tilmelder sig listen, vælger de, hvilke typer af informationer de er interesserede i, f.eks. uddannelser og Buzz Talks. Udsendelse af emails sker ved, at en medarbejder ved IT-C går ind på en administrationsside, hvori emailen indtastes og sendes.

Opgave 1 (20 procent) - HTML

Nedenfor vises indgangssiden for den web-baserede nyhedsliste:

Indgangssiden indeholder tre formularer (HTML-tag <form ...>) svarende til de tre kasser: "Tilmelding", "Kontrol" og "Afmelding". Siden giver mulighed for, at personer kan

  1. Tilmelde sig nyhedslisten ved bl.a. at angive email og de informationstyper (Buzz Talk, Forskning, Stillinger, Uddannelser), man er interesseret i. Man kan angive 1 eller flere informationstyper.
  2. Kontrollere sin tilmelding, ved at indtaste sin email. Kontrollen viser bl.a., hvilke informationstyper man har registreret.
  3. Afmelde sig fra nyhedslisten.

Opgave 1.1

Opskriv HTML koden for formularen "Kontrol" i siden ovenfor. Besvarelsen skal udelukkende indholde HTML-koden for formularen og ikke HTML koden for hele siden:
  <form method=post action=nl_kontrol.php>
    ...
  </form>
Kassen med teksten "Kontrol" er ikke en del af formularen.

Der er ingen skjulte formvariable i formularen.

Formularen indeholder to form-elementer:

  1. Et indtastningsfelt (<input>) til email, hvor form variablen navngives email.
  2. En submit-knap hvor knappen har teksten "Kontrol".

Opgave 1.2

Opskriv HTML koden for formularen "Tilmelding" i siden ovenfor. Besvarelsen skal udelukkende indeholde HTML-koden for formularen og ikke HTML-koden for hele siden:
  <form method=post action=nl_tilmeld.php>
    ...
  </form>
Den sorte ramme er ikke en del af formularen.

Der er ingen skjulte formvariable i formularen.

Formularen indeholder følgende fem form-elementer:

  1. Et indtastningsfelt til navn, hvor form variablen navngives name.
  2. Et indtastningsfelt til telefon, hvor form variablen navngives phone.
  3. Et indtastningsfelt til email, hvor form variablen navngives email.
  4. Fire knapper til informationstyperne der alle navngives info. Værdierne af hver knap sættes til henholdsvis 1 for Uddannelser, 2 for Stillinger, 3 for Forskning og 4 for Buzz Talks. Man skal kunne klikke (vælge) flere knapper samtidigt.
  5. En submit-knap hvor knappen har teksten "Tilmeld mig".

Opgave 1.3

I denne opgave skal du skrive en funktion nl_return_page, som returnerer HTML-koden, der omgiver formularerne på indgangssiden. Funktionen tager to argumenter title og body. Indgangssiden kan genereres ved at kalde nl_return_page med title sat lig "IT-højskolens nyhedstjeneste" og body sat lig de tre formularer (jvf. billedet med indgangssiden vist ovenfor):
  function nl_return_page($title,$body) {
      echo "<html>\n";
        ##her skal der være HTML##
     echo "</html>\n";
  }
Der er følgende krav til siden: Bemærk, at den sorte ramme rundt om hele siden ikke er en del af den HTML-kode, som du skal skrive.

Du skal opskrive kode for programpunktet ##her skal der være HTML##.

Opgave 2 (20 procent) - SQL

Datamodellen for nyhedslisten består af tre tabeller:
  1. nl_user - indeholder data om de tilmeldte personer
  2. nl_info - indeholder de mulige informationstyper, dvs. Buzz Talk, Forskning, Stillinger og Uddannelser
  3. nl_user_info - indeholder informationstyper knyttet til de tilmeldte personer
Datamodellen er tegnet nedenfor. De firkantede kasser angiver tabellerne. En tabels navn er skrevet øverst, og tabellens felter er angivet under tabellens navn. En-til-mange relationer er angivet med kragefødder; eksempelvis kan en person i nl_user have 1 eller flere informationstyper i tabellen nl_user_info.

Tabellen nl_info er oprettet ved følgende SQL kommando:

CREATE TABLE nl_info (
	info_id INT AUTO_INCREMENT PRIMARY KEY, 
	info_name VARCHAR(40) NOT NULL,
UNIQUE (info_name)
) 
  )
Følgende SQL insert kommandoer kan efterfølgende antages at være udført:
  INSERT INTO nl_info (info_name) VALUES ('Uddannelser');
  INSERT INTO nl_info (info_name) VALUES ('Stillinger');
  INSERT INTO nl_info (info_name) VALUES ('Forskning');
  INSERT INTO nl_info (info_name) VALUES ('Buzz Talks');

Opgave 2.1

Vis resultatet af at udføre følgende SELECT kommando:
  SELECT info_id, info_name FROM nl_info ORDER BY info_name

Opgave 2.2

Opskriv en SQL-kommando til at oprette tabellen nl_user. Tabellen skal have fem felter (kolonner): Opskriv en SQL kommando til at oprette tabellen nl_user_info. Tabellen skal have to felter:

Vælg de rigtige datatyper og attributter.

Opgave 2.3

Skriv en SQL-kommando til indsættelse af følgende person i tabellen nl_user: navn "Anders And", telefon "34 32 56 43" og email "anders@andeby.dk". Sæt user_id lig 1 og create_date lig dagsdato.

Skriv en SQL kommando som knytter personen Anders And (med user_id lig 1) til informationstypen Buzz Talks (info_id lig 4).

Opgave 2.4

Konstruer en SQL kommando til udtrækning af alle personer, som skal modtage nyheder, der vedrører informationstypen "Uddannelser" (info_id lig 1).

Følgende kolonner skal indgå i resultatet: name, email, info_name, user_id og info_id.

Rækkerne ønskes sorteret stigende efter email.

Vink: SQL kommandoen skal hente data fra de tre tabeller nl_user, nl_user_info og nl_info.

Opgave 2.5

Konstruer en SQL kommando, som returnerer antallet af personer, der har tilmeldt sig hver informationstype.

Kolonnerne i resultatet skal være name og count (dvs. antallet af personer tilmeldt den pågældende informationstype). Resultatet skal være sorteret stigende efter kolonnen name.

SQL kommandoen kan eksempelvis returnere:

       COUNT NAME
  ---------- -----------
           2 Buzz Talks
           3 Forskning
           3 Stillinger
           3 Uddannelser
Der er to personer, som har tilmeldt sig Buzz Talks osv.

Vink: SQL kommandoen skal hente data fra de to tabeller nl_info og nl_user_info og desuden benytte SQL's group by konstruktion.

Opgave 3 (20 procent) - PHP

i filen functions_db.inc.php findes funktionerne executeSQLSelect() og executeInsert() som tager attributten $strSQL og returnere en pointer til relevant resultatsæt.

Opgave 3.1

Vis HTML-koden, som er resultatet af at køre PHP-koden vist nedenfor (dvs. HTML-koden som returneres ved kaldet til gen_info_buttons).

Indholdet af tabellen nl_info er som i opgave 2.1.

function gen_info_buttons($group_name)	{
	include("functions_db.inc.php");
	$result = executeSQLSelect("SELECT info_id, info_name FROM nl_info order by info_name");
	
 	$strOutput =  "<blockquote>\n";
	while($arrRow = mysql_fetch_array($result))	{
      $strOutput =$strOutput."\t<input type=checkbox name=\"$group_name\" value=\"".$arrRow["info_id"]."\">". $arrRow["info_name"]."<br>\n";
    }
		$strOutput =$strOutput."</blockquote>\n";
      $strOutput =$strOutput."\n";
    return $strOutput;
  }

echo gen_info_buttons ("info");
Bemærk: Hvis du ikke har løst opgave 2.1, så skal du kigge på INSERT-kommandoerne lige før opgave 2.1.

Opgave 3.2

Betragt arrayet $arrCounts
 $arrCounts = array(2, 3, 2, 3);
Hvad er resultatet af at udføre php-koden nedenfor (dvs. hvad returnerer kaldet til calc_sum).
  function calc_sum($arrCounts) {
    $sum = 0;
	for($i=0;$i<(count($arrCounts));$i++)	{
      $sum =  $sum + $arrCounts[$i];
    }
    return $sum;
  }
  
echo calc_sum($arrCounts);

Du skal angive resultatet med 1 decimal.

Opgave 3.3

Vi betragter igen arrayet $arrCounts fra opgave 3.2 samt arrayet $arrNames:
  $arrNames = array("Buzz Talks", "Forskning", "Stillinger", "Uddannelser"]
Du skal skrive en funktion calc_pct, som givet de to arrays $arrCounts og $arrNames som argumenter returnerer følgende HTML-kode (der må gerne være et vilkårligt antal decimaler før %-tegnet):
  <ul>
    <li><b>Buzz Talks</b>: 2(20.00%)
    <li><b>Forskning</b>: 3(30.00%)
    <li><b>Stillinger</b>: 2(20.00%)
    <li><b>Uddannelser</b>: 3(30.00%)
  </ul>
Det første element i arrayet $arrCounts (2) er antallet af tilmeldinger til første informationstype i arrayet $arrNames (Buzz Talks) osv.

For hver informationstype angives i procent antallet af tilmeldinger ud af samtlige tilmeldinger; eksempelvis er 2 ud af i alt 10 tilmeldinger 20.00% (2 / 10 * 100 = 20.00).

Du kan anvende følgende skabelon:

function calc_pct($arrCounts,$arrNames)	{
	$iSum = calc_sum($arrCounts);
	$strInfos = "<ul>\n";
	for($i=0;$i<count($arrCounts);$i++)	{
		$strInfos = $strInfos."<li>";
##A## } $strInfos = $strInfos ."</ul>\n"; return $strInfos; } Du skal opskrive kode for programpunktet ##A##.

Opgave 4 (10 procent) - Regulære udtryk

Opgave 4.1

Betragt det regulære udtryk
^[1-9][0-9]*$

Hvilke af følgende fem strenge matches af det regulære udtryk ovenfor:

Opgave 4.2

På nyhedslisten definerer vi et telefonnummer til at være en måske tom sekvens af tal, der gerne må være adskilt af mellemrum og - (bindestreg).

Følgende strenge er gyldige telefonnumre:

Følgende strenge er ikke gyldige telefonnumre: Opskriv et regulært udtryk, der matcher telefonnumre, som defineret ovenfor.

Vink: Der er ikke nogen øvre grænse på længden af et telefonnummer.

Opgave 5 (30 procent) - Web-service

Til konstruktion af php-filerne, som implementerer nyhedslisten, er der opstillet tilstandsdiagrammet på side 11. Kasserne i tilstandsdiagrammet repræsenterer web-sider og pilene repræsenterer de php-programmer, der afvikles for at komme fra en web-side til en anden.

Opgave 5.1

Nedenfor følger en skabelon til filen nl_tilmeld.php, som tilmelder en ny person til nyhedslisten.

Formvariablene name, phone, email og info modtages fra tilmeldingsformularen på indgangssiden.

Funktionen set_form_var_as_list returnerer et array med de informationstyper, som brugeren har valgt på indgangssiden. Hvis informationstyperne Buzz Talks og Uddannelser er valgt, så returneres dette array (svarende til info_id i tabellen nl_info):

array(4, 1)
Vi har simplificeret opgaven ved ikke at checke formvariable; vi checker dog, at der mindst er valgt en informationstype.

//expecting formvariables: name, phone email and info (an array).
include("functions_db.inc.php");

if(count($info)==0)	{
	nl_return_page("Tilmelding","Du skal angive mindst en informationstype før du kan tilmeldes.");
}
$result = executeSQLInsert("INSERT INTO nl_user ##A##");

if(!$result) 	{
//the insert went wrong; assume it is because the 
//email is already in the user table

	nl_return_page("Tilmelding","Vi kan ikke registrere din tilmelding, idet den indtastede email allerede er registreret.");
}else{
//fetching the new user and putting it in the $arrNewUser
	$result = executeSQLSelect("SELECT MAX(user_id)FROM nl_user");
	$arrNewUser = mysql_fetch_row($result);
	
  	for($i=0;$<count($arrInfo);$i++)	{
		$result = executeSQLInsert(##B##);
   }
   nl_return_page("Tilmelding","Tak for din tilmelding.");
Opgaven består i at opskrive kode for programpunkterne ##A## og ##B## i skabelonen ovenfor.

Opgave 5.2

I denne opgave skal du konstruere dele af filen nl_kontrol.php, som viser registreret information om allerede tilmeldte personer.

Formvariablen email modtages fra kontrolformularen på indgangssiden. Vi har simplificeret opgaven ved ikke at checke formvariablen.


//expecting form variable: email
include("functions_db.inc.php");
$strSQL = "SELECT user_id, name, phone, create_date FROM nl_user WHERE nl_user.email = '$email'";
$result = executeSQLSelect($strSQL);
if(mysql_num_rows($result)==0) {
    nl_return_page("Kontrol","Den indtastede email er ikke registreret i nyhedstjenesten.");
}else{
 ###variablerne sættes###
}

$strBody = "<b>$name</b> er registreret den $create_date med <p>
      email: <b>$email</b>, <p>
      telefon: <b>$phone</b> og følgende informationstyper:<p>
      <ul>\n";
	  
	    $strSQL = "SELECT nl_info.info_name
					FROM nl_user_info, nl_info 
                	WHERE nl_user_info.info_id = nl_info.info_id 
                  	AND nl_user_info.user_id = '$user_id'
                	ORDER BY nl_info.info_name";
					
		$result = executeSQLSelect($strSQL);
		   ##A##	   
	$strBody =. "</ul>";
    nl_return_page("Kontrol",$strBody)
  
Du skal opskrive kode for programpunktet ##A##, som skal tilføje HTML-kode til variablen body, således at body også indeholder en "bullet"-liste (tag <ul>) med de informationstyper som brugeren er tilmeldt.

Opgave 5.3

I denne opgave skal du konstruere filen nl_afmeld.php, som sletter en person fra databasen.

Formvariablen email modtages fra afmeldingsformularen på indgangssiden. Vi simplificerer opgaven ved ikke at checke formvariablen.

// expecting form variable: email
include("functions_db.inc.php");
$strSQL = "SELECT user_id FROM nl_user WHERE email = '$email'";
$result = executeSQLSelect($strSQL);
  ##A##
Du skal opskrive kode for programpunktet ##A##, som skal se, om personen findes i tabellen nl_user. Hvis dette ikke er tilfældet, returneres en fejlside (med nl_return_page, Opgave 1.3), ellers slettes personen fra tabellen nl_user og nl_user_info og der returneres en side med information om, at personen er slettet (med nl_return_page).

Vink: Til at finde ud af om personen allerede findes i nl_user, kan du f.eks. anvende php-funktionen mysql_num_rows().

Opgave 5.4

I denne opgave skal du konstruere dele af filen nl_stat.php.

Der overføres ikke nogen formvariable til nl_stat.php.

  function calc_sum($arrCounts) {
    -- Som vist i opgave 3.2 --
  }

  function calc_pct($arrCounts,$arrNames) {
     -- Dit svar i opgave 3.3 --
  }

  $strSQL = "-- Dit svar i opgave 2.5 --";
  
  // expecting form variable: email
include("functions_db.inc.php");
$result = executeSQLSelect($strSQL);

  ##A##

  nl_return_page("Statistik","Af de registrerede personer på nyhedslisten fordeler interessen sig således:"
    <blockquote>
    calc_pct($arrCounts,$arrNames)
    </blockquote>"
Du skal opskrive kode for programpunktet ##A##, som går ud på at opbygge to arrays: $arrCounts og $arrNames svarende til de i opgave 3.3.

Vink: Du skal anvende en løkke (for eller while)

Opgave 5.5

Du skal skrive en php-fil nl_send.php, som givet en informationstype og indhold af en email, sender emailen til alle personer på nyhedslisten, som er tilknyttet informationstypen.

Filen nl_send.php modtager formvariablene info, subject, content og sender.

Vi simplificerer opgaven ved ikke at checke formvariablene samt antager, at der kun modtages en informationstype.


 // Expect form variables: sender, subject, content and info
 $strSQL = "-- Dit svar på opgave 2.4 med info_id = 1 erstattet af info_id = '$info_id'";
  ##A##
Du skal opskrive kode til programpunktet ##A##, der med php-kommandoen mail() sender en email til de personer, som forespørgslen returnerer.

Der skal returneres en side til brugeren, som viser navn og email på dem, der er sendt en email til.