Nyhedssystem med brugerkommentarer
Jeg har fået indtryk af at en del Udviklere finder det vanskeligt at lave et nyhedssystem med kommentarer i PHP/MySQL. Der er jo allerede en masse artikler her på Udvikleren.dk om hvordan man putter ting i en database og hiver dem ud igen, så i princippet burde det jo ikke være så svært. Jeg tror lidt at det er når kommentarer skal hænge sammen med en nyhed, at det bliver lidt svært for nogen. Hvordan skal det laves i databasen? Skal det hele placeres i samme tabel, eller deles op over flere? Hvordan hiver man kommentarer ud til en specifik nyhed? Alt dette vil blive besvaret længere nede...
Det er i øvrigt værd at nævne, at selvom et nyhedssystem lyder meget simpelt, så kan det jo også bruges til meget andet. Personligt har jeg lavet et såkaldt blog (weblog) system, ud fra de teknikker der vil blive vist i denne artikel, og med lidt modificering, kan koden også bruges til mange andre ting. Denne artikel forudsætter at du ved lidt om PHP, ved hvordan du tilslutter dig til en MySQL database osv. Der vil ikke være kode til et komplet system, men derimod en del teori samt kode der kan sættes sammen til et fuldt funktionelt system. Dem der gerne vil lære lidt mere og PHP og/eller MySQL, bør kigge på
http://www.udvikleren.dk/show_articles.php?kat=6 (PHP/MySQL artikler).
Databasetabeller
Ja, så har jeg vist allerede afsløret at vi skal bruge mere end én tabel

. For dem der ved lidt om design af databaser, vil dette virke meget logisk, men jeg forklarer det nu alligevel!
Vi opretter to tabeller, en til kommentarer og en til nyheder, og knytter dem så til hinanden med et ID – dette kaldes en relation. I fx Access vil man oprette denne relation og kunne se den, men i MySQL tænker man sig lidt til den

. Når vi henter kommentarer, vil de allesammen have knyttet en nyhed til sig, via et ID. Jeg vil nu vise tabelstrukturerne, så i bedre kan danne jer et overblik over hvad jeg mener:
create table nyheder (
id int(6) not null primary key auto_increment,
emne varchar(255),
forfatter varchar(100),
dato datetime,
nyhed text
);
create table kommentarer (
id int(10) not null primary key auto_increment,
nyhedsid int(6),
forfatternavn varchar(100),
forfattermail varchar(150),
dato datetime,
kommentar text
);
Tabellerne oprettes lettest ved at smide det hele ind i SQL feltet under PHPMyAdmin, hvis det er tilgængeligt. Ellers kan det gøres gennem en Telnet-session eller lignende

.
Som lovet vil jeg gerne forklare lidt omkring teorien bag den måde at bygge systemet op på, nærmere beteget den måde nyhederne og kommentarerne er knyttet sammen. Jeg har allerede fortalt lidt om det, men da jeg tror at det er på netop dette punkt at en del Udviklere kommer i tvivl, vil jeg lige slå det helt fast: Hver nyhed og hver kommentar har sit eget, unikke ID. Hver kommentar har også et nyhedsid, der hænger sammen med et unikt ID på en nyhed. På den måde er en nyhed ikke knyttet til en kommentar (det ville ikke give nogen mening), men en kommentar er altid knyttet til en nyhed. Dette kaldes en en-til-mange relation, da hver nyhed kan have mange kommentarer, men hver kommentar kun kan have én nyhed. Når vi vil hente kommentarer for en nyhed, kan vi bare hente dem der har det nyhedsid for den nyhed som vi gerne vil vise kommentarer for. Det kan måske lyde lidt kryptisk - forstår du det ikke første gang, kan det godt læses flere gange, da det er et vigtigt element i måden at lave databasesystemer på.
Når tabellerne er oprettet, skal vi i gang med det sjove: PHP koden

Noget kode...
Mere skal der sådan set ikke til. Nu skal vi så have lidt kode til at hive noget data ud, men til at starte med vil det nok være smartere at oprette noget HTML/PHP kode, der kan indsætte ting i databasen. Det der skal bruges er sådan set bare en formular til at indsætte nyheder i systemet (man kan enten selv lave noget, eller bruge PHPMyAdmin til opgaven), og så en formular hvor brugerne kan indtaste kommentarer til nyhederne. Det sidste kan du se i eksemplet, hvordan jeg har gjort.
Nu følger lidt kode der viser hvordan man hiver alle nyheder ud af databasen, og viser dem én efter én. Der bliver samtidig lagt et link kommentarerne. Dette link aktiverer et popup-vindue, hvor brugerne kan læse eksisterende kommentarer, samt skrive en ny. Dette kan naturligvis sagtens gøres anderledes, det er bare at være lidt kreativ og så bytte lidt rundt på koden

.
<?
// Vis alle nyheder
// Husk at der skal være en databaseforbindelse her
$getnews = mysql_query("select id, emne, forfatter, dato, nyhed from nyheder order by dato desc");
if(mysql_num_rows($getnews) > 0)
{
while($r = mysql_fetch_array($getnews))
{
$nyhedsid = $r[id];
$emne = stripslashes($r[emne]);
$forfatter = $r[forfatter];
$dato = $r[dato];
$nyhed = stripslashes(nl2br($r[nyhed]));
// Vi henter nu antallet af kommentarer til denne nyhed
$getcommentcount = mysql_query("select COUNT(id) from kommentarer where nyhedsid='".$nyhedsid."'");
$antalkommentarer = mysql_result($getcommentcount,0,0);
// Vi udskriver nyheden og antallet af kommentarer
echo "<b>".$emne."</b> - skrevet af ".$forfatter." d. ".$dato;
echo " (<a href="#" onclick="window.open('kommentarer.php?id=".$nyhedsid."','flyout',
'toolbar=no,location=no,directories=no,status=no,menubar=no,resizable=no,
scrollbars=yes,width=400,height=600,top=25,left=25')">
".$antalkommentarer." kommentarer</a>)";
echo "<br />".$nyhed;
}
}
else
{
echo "Endnu ingen nyheder tilføjet.";
}
?>
Så simpelt er det

. Jeg forklarer lidt om hvad de enkelte linier gør: Vi lægger hårdt ud med en SQL forespørgsel. Den er meget simpel, og går ganske enkelt bare ind og henter alle nyheder i tabellen, og sorterer dem efter dato (nyeste først - desc). Derefter tjekker vi om forespørgslen giver et antal rækker tilbage over 0. Hvis det er tilfældet er der nyheder som vi viser, ellers skriver vi en fin besked til brugeren om at der endnu ikke er tilføjet nogen nyheder. Vi bruger nu en while løkke til at løbe igennem alle resultaterne af forespørgslen. For hver gang vi itererer gennem while-løkken, placerer vi et array af den række i $r. På den måde kan vi nu kigge i $r, for at finde de info vi har hevet ud af tabellen – det gør vi så for at hente emne, forfatter, dato og nyhed ud.
Med nyhed laver vi lige et par ekstra tricks. For det første bruger vi stripslashes, der sørger for at fjerne eventuelle \\ tegn der er tilføjet (bliver tilføjet hvis man bruger ” eller ’ tegn i nyheden), hvilket vi også gør på emne. Derudover vil vi gerne have at eventuelle linieskift rent faktisk vises, så med nl2br konverterer vi dem til <br> tags.
Det eneste vi nu mangler, er det med kommentarerne. Vi vil jo gerne være lidt brugervenlige, så i stedet for bare et normalt link til at skrive/læse kommentarer, vil vi også lige fortælle brugeren hvor mange kommentarer der allerede er tilføjet. Vi gør det med en SQL forespørgsel der tæller antallet af rækker med det nyhedsid vi kigger på lige nu, og derefter et mysql_result, der giver resultatet af COUNT funktionen. Når det er klart, har vi de variabler vi skal bruge, og udskriver nyheden. Det er der ikke så mange ben i, måske lige bortset fra det stykke JavaScript der er med. Det gør simpelthen bare at der åbnes et nyt lille vindue til læsning/skrivning af kommentarer.
Som du kan se, linker vi, via JavaScript koden, til en fil der hedder kommentarer.php. Det er den vi gerne vil have til at vise vores kommentarer. Det kræver lige lidt mere kode, da jeg også viser hvordan man kan opstille en formular til at lade brugeren tilføje kommentarer. Så selvom jeg påstod at der ikke vil være en komplet løsning til denne artikel, så er det faktisk ved at være tæt på

. Her kommer lidt kode, og derefter en forklaring.
<?
// Vis alle kommentarer for en nyhed
// Husk at der skal være en databaseforbindelse her
if($_POST[id])
{
$nyhedsid = $_POST[id];
}
else
{
$nyhedsid = $_GET[id];
}
if(!$nyhedsid)
{
echo "Intet nyheds-id angivet.";
}
else
{
if($_POST[add_comment])
{
$navn = $_POST[navn];
$mail = $_POST[mail];
$kommentar = addslashes($_POST[kommentar]);
$addcomment = mysql_query("insert into kommentarer (nyhedsid, forfatternavn, forfattermail, kommentar, dato)
VALUES ('".$nyhedsid."','".$navn."','".$mail."','".$kommentar."',NOW())");
if($addcomment)
{
echo "Din kommentar er tilføjet. Mange tak.<br /><br />";
}
else
{
echo "Fejl: ".mysql_error();
}
}
$getcomments = mysql_query("select id, forfatternavn, forfattermail, dato,
kommentar from kommentarer where nyhedsid='".$nyhedsid."'");
if(mysql_num_rows($getcomments) > 0)
{
while($r = mysql_fetch_array($getcomments))
{
$kommentar = stripslashes($r[kommentar]);
$dato = $r[dato];
$forfatternavn = $r[forfatternavn];
$forfattermail = $r[forfattermail];
echo "<a href="mailto:".$forfattermail."">".$forfatternavn."</a> - ".$dato."<br />";
echo $kommentar."<br /><br />";
}
}
else
{
echo "Ingen kommentarer tilføjet til denne nyhed endnu.";
}
?>
<hr>
<form action="<?=$_SERVER[PHP_SELF];?>" method="post">
<input type="hidden" name="id" value="<?=$nyhedsid;?>">
Dit navn:<br>
<input type="text" name="navn" class="input"><br><br>
Din e-mail adresse:<br>
<input type="text" name="mail" class="input"><br><br>
Kommentar:<br>
<textarea cols="0" rows="5" name="kommentar" class="input"></textarea><br><br>
<div align="center"><input type="submit" name="add_comment" value=" - Tilføj - " class="button">
</form>
<?
}
?>
Vi starter lidt blødt ud med en masse linier kode, der egentlig gør meget lidt. For at være sikker på at vi hele tiden har styr på id’et der angiver nyheden og i første omgang kommer fra nyheds-siden, laver vi lige lidt fix-faxerier

. I de ”gode” gamle dage sagde man jo bare $id, der så kunne komme fra cookies, GET, POST eller noget helt andet, men det er jo (heldigvis, kan man så sige) nu ændret. Derfor er vi nødt til at tjekke om $id bliver smidt af et POST request (vores formular). Gør det det, tager vi det derfra, og ellers så tager vi det fra GET (fra siden med nyhederne). For en sikkerheds skyld tjekker vi lige om den har en værdi, for hvis den ikke har det, så er der ingen grund til at begynde på MySQL osv. Så altså, har vi ikke et id på en nyhed, så udskriver vi kun en fejl om det til brugeren – ellers henter vi kommentarer (hvis der er nogen), og viser en formular der lader brugeren tilføje.
Det første vi gør, hvis vi har et nyhedsid, er at tjekke om brugeren har forsøgt at tilføje en kommentar. Dette gør vi ved at tjekke på POST variablen add_comment, som er navnet på knappen. Er denne variabel sat, betyder det at brugeren gerne vil tilføje en kommentar, så det gør vi. Man kan evt. tilføje lidt validering ved at tjekke om navn og mail er sat, på samme måde som jeg tjekker på add_comment, men da det nok ikke er alle der synes at det er relevant at tage med til så simpelt et system, har jeg udeladt det. Anyway, hvis der skal tilføjes en kommentar, henter vi alle variablerne ud af POST, og tilføjer \\ tegn til kommentar med addslashes (for at undgå MySQL fejl hvis brugeren indtaster ” eller ’ tegn). Derefter kører vi en simpel INSERT SQL forespørgsel, tjekker om den er gået godt, og udskriver enten en fejl eller en ”Tak for kommentaren”-notits

. Der fra er det faktisk meget simpelt: Vi laver en SQL forespørgsel der henter alle kommentarer til den nyhed vi har angivet med nyhedsid, og viser dem på præcis samme måde som vi gjorde det med selve nyhederne. Til sidst har vi så den HTML formular der lader brugeren tilføje en kommentar, og som omtales længere oppe.
Færdig?
Ja, der er vel ikke så meget mere at sige. Selvfølgelig er der ting der kunne gøres pænere, først og fremmest designet, som jeg overhovedet ikke har rørt ved

. Derudover er der ting som dato’en, der kommer ud i amerikansk format, plus nogle andre, mindre, detaljer. Alt dette kan du dog selv gøre noget ved, eller evt. spørge om hjælp til, her på Udvikleren.dk

. God fornøjelse med det...