Adding a newsfeed for your users to a multipage PHP application
Archive - Originally posted on "The Horse's Mouth" - 2009-06-06 23:42:12 - Graham EllisAs I wrote it, I realised this was turning into rather a long article, but never mind. It shows the major new components added to a "4 layer model" application I was working on the weekend before last to add in a newsfeed for logged in users to which they can contribute, together with a headlines-only display for none logged in members. The code may look longish, but it was written and tested very quickly.
If you are not familiar with the 4 layer model, start here or attend our PHP techniques workshop ... this is a more advanced article
In the particular multi page application I was modifying, page #2 is the main navigation menu, so the "finish processing stage 2" code at the top level will branch the user to many other pages in the system. Page #6 is where I added the news update:
case 2: // Navigation request made
if ($_REQUEST[studinfo] == 1) $current = 3;
if ($_REQUEST[studinfo] == 2) { $current = 4;
$fill[topmsg] = "Please enter new user data"; }
if ($_REQUEST[studinfo] == 3) $current = 6;
if ($_REQUEST[studinfo] == 4) $xlevel = 2;
break;
Adding data to the newsfeed is simply done by appending the data to a file, and I've checked when data is submitted that both a title and a body have been given (you'll see a comment requesting this when we come to the template form further down this example). I have used the string "::-::" as a separator / marker in the first line of each new news item in the hope that users will never add such a thing in their data ... and I'm fully aware that if I was writing something for "Joe Public" to enter data into rather that some benign and small club, this would be a bit of a hole; in such a case, I would store to a MySQL database, and within this code might have logic to delete all but the most recent 100 postings.
case 6: // Add to news feed request
if (eregi("[a-z]",$_REQUEST[topbits]) and
eregi("[a-z]",$_REQUEST[bottombits])) {
$now = time();
$fho = fopen("newsfeed.txt","a");
fputs($fho,"$now::-::$_SESSION[username]\n");
fputs($fho,"$_REQUEST[topbits]\n");
fputs($fho,"$_REQUEST[bottombits]\n");
fclose ($fho);
}
$current = 2;
break;
In the 4 layer model, when you've finished handling the data submitted in the form on one page, you prepare for the next. I have added calls to a function I called newsfeed on all pages that I want to display a feed ... here is the example in the logic that prepares for a new news item, which reports a substantial amount of the old news to that the new article author can write in context. You will note that I'm putting the changing data into an array called $fill rather than generating the code directly - this is the element of the 4 layer model which allows me to separate the business logic from the look and feel - exactly what I need to do to allow for maximum future flexibility, and to allow me to pass the maintainance of code to programmers, and of the look and feel to graphic artists!
case 6: // Prepare for adding to news feed
$fill[title] = "OurClub Adding to news feed";
$fill[news] = newsfeed(2);
break;
Here is the actual template ... for ease of understanding for the newcomer (i.e. to avoid ending up with a large number of files for just a demo piece) in this example, we wrote it into a "here string" ... in which we replace %-letters-% with whatever we have in the matching element of the $fill array:
$body_template[6] = <<<CLUB_TEMPLATE
<h1>Add a message to the newsfeed</h1>
Please give a headline and text of article. If you don't want to post
an article after all, just submit a blank page and it won't be added.
<form method=post>
Headline: <input name=topbits><br>
Text of article <textarea name=bottombits rows=20 cols=60></textarea><br>
When you are done ... <input type=submit></form>
<hr><b><u>The latest news feed!</u></b><br><br>%news%<br>
CLUB_TEMPLATE;
Finally, here is the 'business logic' which interprets all of the elements of the newsfeed and returns a string suitable for rendering. You'll note that even at a 'club level', I've added a number of coding / security checks - i.e. all the data the user has entered in the news goes through stripslashes and htmlspcialchars in order to render harmless any attempted injection attacks. What it does NOT do is provide any form of moderation - i.e. checking for news that breaks copyright, is libellous, adult, incites breaking of the law ... that remains a manual process.
function newsfeed($level) {
foreach (file("newsfeed.txt") as $line) {
$lp = explode("::-::",$line);
if (count($lp) == 2) {
$cur_news = $lp[0];
$cur_repo = trim($lp[1]);
$cur_lines = -1;
} else {
if ($cur_lines == -1) {
$art_title[$cur_news] = $line;
$art_autho[$cur_news] = $cur_repo;
$cur_lines = 0;
} else {
$art_text[$cur_news] .= $line;
$cur_lines++;
}
}
} // End of feeder reader
krsort($art_title);
$response = "";
$narts = 3;
foreach (array_keys($art_title) as $tstamp) {
$tsf = date('H:i \o\n l jS M Y',$tstamp);
$an++;
if ($level == 0) {
$response = $art_title[$tstamp];
break;
} elseif ($level == 1) {
$response .= "<br><b><u>$art_title[$tstamp]</u></b> by ".
"$art_autho[$tstamp] at $tsf";
if ($an > $narts) continue;
$response .= "<br><br>";
$response .= nl2br(htmlspecialchars(stripslashes("$art_text[$tstamp]")));
if ($an > $narts * 3) break;
} elseif ($level == 2) {
$response .= "<br><b><u>$art_title[$tstamp]</u></b> by ".
"$art_autho[$tstamp] at $tsf<br><br>";
$response .= nl2br(htmlspecialchars(stripslashes("$art_text[$tstamp]")));
if ($an > $narts * 3) break;
}
}
if ($level == 1) {
$response .= "<br><a href=\"?studinfo=4\">show more</a>";
}
return $response;
}