10 maart 2007
Gezien het aantal hits wat we binnenkrijgen op een eigen CMS bouwen, is hier nogal wat vraag naar. Nu sta ik echter voor een probleem. Ik heb inmiddels een siteje of 100/200 van een CMS voorzien, dus dat zit wel snor - maar wat is de concrete vraag áchter de vraag "Hou bouw ik een CMS?" Wat is de startsituatie van zo'n vragensteller en waar zitten de vragen? Laat ik daarom maar eens beginnen met een omschrijving te geven van de doelgroep die ik met dit artikel heb:
Als jij tot de doelgroep van dit artikel behoort...
SELECT en INSERT en de 90% meest gebruikte PHP functies hebben voor jou geen geheimen meer (of je weet waar je er informatie over kan vinden.De termen 'backoffice' en 'frontoffice' zou ik eigenlijk als bekend willen veronderstellen, maar voor de zekerheid: De backoffice is dat deel van de site waar de content beheerd wordt. Je hebt hier in de regel enkel toegang tot als je over een user/pass combinatie beschikt. De frontoffice is dat deel van de site wat de bezoeker ziet em waar de content wordt geprojecteerd. Je ziet dus dat mijn definitie van "site" zowel de backoffice als de frontoffice beslaat.
Nu is de praktijk van het programmeren dat het bouwen van de backoffice ongeveer 3 keer zo veel werk is als het bouwen van de frontoffice. Als de backoffice (het beheren van content) eenmaal staat, is het uitlezen niet veel werk meer.
Opmerking:
Hier zijn natuurlijk uitzonderingen voor te bedenken. Zeker een usersysteem waarbij de user kan registreren, inloggen, zijn wachtwoord opvragen enz. vraagt redelijk wat werk aan de frontoffice. Pak je echter een nieuwssysteempje, dan is bovenstaande uitspraak zeker waar.
De basis van je PHP werk is je MySQL ontwerp. Vandaar dat de eerste stap van het ontwikkelen van een CMS het ontwerpen van de database is. Omdat we een modulair systeem gaan bouwen, zullen de databases niet al te zeer naar elkaar gelinkt zijn en is het ontwerp dus eenvoudig. Wat ik vaak doe ik een A4'tje maken waarop ik de database uitteken. Deze hou ik altijd bij de hand bij het programmeren.
Voor de backoffice hebben we uiteraard een loginsysteem nodig. Nu is het in de meeste gevallen best afdoende als je via bijvoorbeeld Plesk de betreffende directory beveiligd, maar ik ga nu even uit van een situatie waarin je meerdere users kan hebben. Voor deze users gebruik ik de volgende tabellen:
adminUsers:
+----+------+------+
| id | user | pass |
+----+------+------+
adminPogingen:
+----+--------+------+--------+-------+-----------+----+
| id | userID | user | status | datum | userAgent | ip |
+----+--------+------+--------+-------+-----------+----+Het loginsysteem zelf zal met cookies gaan werken. Voor de veiligheid maken we gebruik van MD5() encryptie voro het wachtwoord. Ook hebben we interesse in het in de gaten houden van wanneer wie heeft ingelogd en of dat gelukt is of niet. Oftewel, alle loginpogingen worden opgeslagen. Voor het inloggen hebben we twee functies nodig:
<?php
function schrijfLoginPogingWeg($user, $userID, $gelukt){
if(!not_null($user)){
$user = "Niet opgegeven";
}
$query = "INSERT INTO " . DB_PRETABLE . "adminPogingen (userID, user, status, datum, userAgent, ip) VALUES ('$user', '$userID', '$gelukt', " . time() . ", '" . $_SERVER['HTTP_USER_AGENT'] . "', '" . $_SERVER['REMOTE_ADDR'] . "')";
mysql_query($query) or die (mysql_error());
}
function checkLogin($user, $pass){
$result = mysql_query(" SELECT *
FROM adminUsers
WHERE user = '" . $user . "'
AND pass = '" . MD5($pass) . "'") or die (mysql_error());
if (mysql_num_rows($result) == 1){
// Er is succesvol ingelogd
$_SESSION['admin_userID'] = mysql_result($result, 0, "id");
$_SESSION['admin_user'] = stripslashes($user);
// Schrijf een succesvolle loginpoging weg
schrijfLoginPogingWeg($user, $_SESSION['admin_userID'], "1");
return true;
}else{
$result = mysql_query(" SELECT *
FROM adminUsers
WHERE user = '" . $user . "'") or die (mysql_error());
if (mysql_num_rows($result) == 1){
// De gebruiker bestaat wel
$userID = mysql_result($result, 0, "id");
}else{
// De gebruiker bestaat wel
$userID = 0;
}
// Schrijf een niet-succesvolle loginpoging weg
schrijfLoginPogingWeg($user, $userID, "0");
return false;
}
}
?>De loginprocedure die we in login.php zetten zal dan iets als dit moeten zijn:
<?php
if (!$_POST['submit']){
// Toon formulier
echo " <h1>Inloggen</h1>
<table border=\"0\">
<form action=\"\" method=\"post\">
<tr>
<td width=\"80\">
<strong>Gebruikersnaam</strong>
</td><td>
<input type=\"text\" name=\"user\" style=\"width:150px;\">
</td>
</tr><tr>
<td width=\"80\">
<strong>Wachtwoord</strong>
</td><td>
<input type=\"password\" name=\"pass\" style=\"width:150px;\">
</td>
</tr><tr>
<td>
</td><td>
<input name=\"submit\" type=\"submit\" value=\"Log in!\">
</td>
</tr>
</form>
</table>";
}else{
// Check login
if (checkLogin($_POST[user], $_POST[pass])){
echo "<h1>Inloggen</h1>";
echo "<p>U bent ingelogd. Eén moment aub...</p>";
echo "<META HTTP-EQUIV=refresh content=2;URL=index.php>";
}else{
echo "<h1>Inloggen</h1>";
echo "<p>Inloggen mislukt. Eén moment aub...</p>";
echo "<META HTTP-EQUIV=refresh content=2;URL=login.php>";
}
}
?>Op elke pagina waar de login verplicht is, zal nu iets als dit moeten komen te staan:
<?php
if(not_null($_SESSION['admin_userID'])){
header('location:index.php');
}
?>Met modulair bouwen doel ik op een CMS waarin je met zeer weinig moeite een extra module kan plaatsen. Dit betekent wat mij betreft dat de modules zeer snel in de backoffice hangen, maar ook dat de afzonderlijke modules niet met elkaar conflicteren. Dat laatste zou kunnen gebeuren als je bijvoorbeeld zowel in je nieuwsmodule als je artikelmodule een functie getItem() gebruikt en de files waarin deze functies staan beiden include.
Als we bijvoorbeeld de backoffice in /beheer zetten, komen de modules in /beheer/modules/$moduleNaam. Dit betekent dat we met een PHP script de modules kunnen langslopen. Stel dat we in elke module-map een bestandje data.php zetten, dan kunnen in die bestandjes bijvoorbeeld de module-naam van het item noemen. Laten we voor nu deze inhoud maar eens in code.php zetten:
<?php
$moduleNaam = "Nieuws";
?>Via onderstaand script kunnen we dan een navigatiestructuur maken zodat we in één menu naar alle beschikbare modules kunnen linken.
<?php
function getModules(){
if ($handle = opendir("modules")){
$return .= "\n<ul>\n";
// Doorloop alle submappen
while (($file = readdir($handle)) !== false){
if($file != "." && $file != ".." && file_exists($file)){
include("modules/" . $file . "/data.php");
$return .= "\t<li><a href=\"index.php?module=" . $file . "\">" . $moduleNaam . "</a></li>\n";
}
}
closedir($handle);
$return .= "</ul>\n";
}
return $return;
}
?>Als je in elke module een bestand output.php maakt met daarin de functies die nodig zijn voor de output, kun je ze op dezelfde manier includen. Let er hierbij wel op dat je voor unieke functienamen zorgt. Een optie zou zijn om de functienamen een prefix te geven die gelijk is aan hun directorie-naam in de map /modules.
22 maart, 2007 - 13:04 | login of registreer om reactie te posten | |
|---|---|
Arjan![]() Aantal berichten: 532 |
Ik zie dit staan: <?phpmoet die Niet dat het waarschijnlijk heel veel uitmaakt, maar toch ;-) |
26 juli, 2007 - 20:23 | login of registreer om reactie te posten | |
|---|---|
| lukeboy_2002 Aantal berichten: 2 |
Na het testen van dit script krijg ik de volgende fout melding: Notice: Undefined variable: return in C:\Program Files\Apache Group\Apache2\htdocs\index.php on line 6 |
26 juli, 2007 - 21:38 | login of registreer om reactie te posten | |
|---|---|
Erik-Jan![]() Aantal berichten: 615 |
Bijzondere foutmelding. Geef de eerste 6 regels van je code eens? |
26 juli, 2007 - 22:45 | login of registreer om reactie te posten | |
|---|---|
Arjan![]() Aantal berichten: 532 |
als je de witruimte uit het voorbeeld weghaalt, kom je idd op regel 6 op de regel uit, waar ik het in mijn vorige post over had. heeft het misschien daar mee te maken? |
28 juli, 2007 - 12:01 | login of registreer om reactie te posten | |
|---|---|
| lukeboy_2002 Aantal berichten: 2 |
dit is mijn code volgens mij compleet dezelfde als hier boven: <?php |
28 juli, 2007 - 12:59 | login of registreer om reactie te posten | |
|---|---|
Arjan![]() Aantal berichten: 532 |
als ik het goed zie is regel 6 deze: <?phpJe plakt daar een string meteen aan een variabele die nog niet eerder is gedefinieerd. Nu is php wel een ranzig taal en zou dat best kunnen werken, maar je zou kunnen proberen om bovenaan in de functie de variabele te 'declareren' met een lege string. Dus: <?php |
28 juli, 2007 - 13:01 | login of registreer om reactie te posten | |
|---|---|
Erik-Jan![]() Aantal berichten: 615 |
Lukeboy, je zou eens kunnen proberen om |