Text Based Article System
With PHP
December 5, 2009<?PHP
/*--------------------------------------------------------------------------\
| These lines will get the information from the URL, for handling the data. |
| There is some filtering here to avoid some kinds of attacks. |
| To reduce processing time, the POST variables are only handled when the |
| script is in "post" mode. |
\--------------------------------------------------------------------------*/
$mode = $_GET['mode'];
$articleID = preg_replace("/[^0-9]/i", "", $_GET['id']);
/*--------------------------------------------------------------------------\
| SWITCH selects the variable that CASE will use. Here, we're using CASE to |
| determine what mode we're in. This allows us to use only one script to |
| handle an entire system -- easy for updates, and cleaner for your htdocs |
| folder.
\--------------------------------------------------------------------------*/
SWITCH ($mode)
{
CASE "add":
{
/*--------------------------------------------------------------------------\
| Here, we'll generate the form that people will create an article in. |
| The action= portion tells the script to point to itself, but in post mode |
| This allows you to name your file whatever you like. |
\--------------------------------------------------------------------------*/
echo "
<form action='" . $_SERVER['PHP_SELF'] . "?mode=post' method='post'>
<label>Title:</label> <input type='text' name='title' /><br />
<label>Author:</label> <input type='text' name='author' /><br />
<label>Body:</label> <textarea cols='25' rows=20' name='body'></textarea><br /><br />
<input type='submit' value='Add Article' />
</form>";
break;
}
CASE "view":
{
/*--------------------------------------------------------------------------\
| Here, the script will open the article, and do some basic formatting to |
| the layout. Also convert the [br]s to <br />s. |
\--------------------------------------------------------------------------*/
if (file_exists($articleID . ".txt"))
{
$file = fopen($articleID . ".txt","r");
$title = trim(fgets($file));
$author = trim(fgets($file));
$time = trim(fgets($file));
$body = str_ireplace("[br]", "<br />", trim(fgets($file)));
fclose($file);
echo "<h1>" . $title . "</h1><hr />Posted By: " . $author . "<hr />" . $body;
}
else
{
echo "Oops! That article doesn't exist!";
}
break;
}
CASE "post":
{
/*--------------------------------------------------------------------------\
| This is where the code starts getting complex. Here, we're writting to a |
| text file, but we have to make sure the data is safe to post. We'll start |
| by cleaning out and formatting the variables first. |
\--------------------------------------------------------------------------*/
$title = strip_tags($_POST['title']);
$author = strip_tags($_POST['author']);
$body = str_replace("\r\n", "",str_ireplace("<br />", "[br]",nl2br(strip_tags($_POST['body']))));
/*--------------------------------------------------------------------------\
| As you can see, the filtering for $body is the most complicated. What all |
| those extra parts do, is convert "newlines" (or when you pressed enter in |
| the textbox) to a pseudo-tag [br]. This makes it safe to put into your |
| text file database, because each field is seperated by an ENTER |
\--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------\
| Below, we're going to use a UNIX timestamp to name the text file, which |
| will become the ID of the file, and help us assess the time it was posted |
\--------------------------------------------------------------------------*/
$posttime = time();
if (file_exists($posttime . ".txt"))
{
/*--------------------------------------------------------------------------\
| Because we're using the timestamp as the filename, it is possible that |
| two people could post at the same time. This is called a "race condition" |
| and is quite a problem for programmers. You could use a random number, |
| but then there's more of a risk of overwritting other files. This code |
| checks to see if the file exists, and if it does, it asks the author to |
| resubmit, thus giving it a new ID number due to the new timestamp. |
\--------------------------------------------------------------------------*/
echo "OOPS! Minor error, please hit back and try again!";
die;
}
/*--------------------------------------------------------------------------\
| Okay, now we're going to actually write the file. As you can see, there's |
| a \r\n at the end of each file. For Windows servers, this means "return |
| carriage" and "new line"...Kinda like a typewritter. For Unix based |
| servers, change it to \r, and Macintosh servers, change to \n. |
\--------------------------------------------------------------------------*/
$file = fopen($posttime . ".txt","w");
fwrite ($file, $title . "\r\n");
fwrite ($file, $author . "\r\n");
fwrite ($file, $posttime . "\r\n");
fwrite ($file, $body . "\r\n");
fclose($file);
/*--------------------------------------------------------------------------\
| Alright, our article is now saved. If you open the text file, you'll see |
| something like this: |
| File Based Article System |
| robert-lerner.com |
| 12345678 |
| Hello![br] In this article, we'll show you how to:[br] Use PHP... |
| Next, we have to create an INDEX file. We'll APPEND the new article: |
\--------------------------------------------------------------------------*/
$file = fopen("index.txt","a");
fwrite ($file, $posttime . "\r\n");
fwrite ($file, $title . "\r\n");
fwrite ($file, $author . "\r\n");
fclose($file);
/*--------------------------------------------------------------------------\
| Now that it's all set, we'll give the author a link to their article. |
\--------------------------------------------------------------------------*/
echo "Thanks for your article! You can view it <a href='" . $_SERVER['PHP_SELF'] . "?id=" . $posttime . "&mode=view'>Here</a>!";
break;
}
DEFAULT:
{
/*--------------------------------------------------------------------------\
| When no MODE is specified, the SWITCH statement defaults to the DEFAULT |
| area. Here, we'll show an index of the articles made -- that way your |
| user's aren't left guessing the ID of a particular article. |
\--------------------------------------------------------------------------*/
echo "<a href='" . $_SERVER['PHP_SELF'] . "?mode=add'><strong>Add an Article</strong></a><br /><br />";
if (file_exists("index.txt"))
{
echo "
<table width='50%' border='1' cellspacing='0' align='center'>
<tr>
<th>Title</th>
<th width='20%'>Posted By:</th>
</tr>";
/*--------------------------------------------------------------------------\
| Here, we're going to open the index file, and format it into a table. |
| Remember that the POSTTIME is also the ID, so we'll exploit that here. |
| There is also a $cnt variable -- this counts the articles, and puts that |
| at the bottom of the table. |
\--------------------------------------------------------------------------*/
$file = fopen("index.txt","r");
while (!feof($file))
{
$id = trim(fgets($file));
$title = trim(fgets($file));
$author = trim(fgets($file));
if ($id!="")
{
echo "<tr><td><a href='" . $_SERVER['PHP_SELF'] . "?id=" . $id . "&mode=view'>" . $title . "</a></td><td>" . $author . "</td></tr>";
$cnt++;
}
}
fclose($file);
echo "</table>" . $cnt . " article(s) in our database.";
}
else
{
/*--------------------------------------------------------------------------\
| If there is no index file, let them know here. |
\--------------------------------------------------------------------------*/
echo "Oops! Seems like we don't have any articles yet. Please add one!";
}
break;
}
}
?>