PHP5:
Code:
function file_prepend_contents($filename, $data) {
file_put_contents($filename, $data.file_get_contents($filename));
}
PHP4:
Code:
function file_prepend_contents($filename, $data) {
$fh = fopen($filename, 'w');
fwrite($fh, $data.file_get_contents($filename));
fclose($fh);
}
Untested but I don't see why they wouldn't work. That said, your method is a little clunky.
Have you considered using XML? It's certainly ideal for something like this, and although probably more difficult to get to grips with it would be more robust and extensible.
If you think that's a bit much, you can make your plain text method a little less clunky.
First off, leave the markup out altogether and add it at the presentational stage - that is, when you're displaying the entries, not inserting them. Much easier to update, much easier to sanitise.
Second, it doesn't really matter which way round you store your entries as you're going to have to parse the whole file anyway. I personally would go for a system whereby you separate the entries with a sequence of characters, split them into an array, and then you can sort them/randomise them/do whatever you want with them.
So, abstracting (is that even a word? ah well) things into functions, you can do:
Code:
<?php
$file = 'guestbook.txt';
if(!file_exists($file)) {
if(!touch($file)) {
die('Unable to create file. Check yo permissions, dawg');
}
}
function sanitise($string) {
return str_replace('#', '£', htmlentities($string));
}
function add_entry($name, $subject, $message) {
global $file;
$name = sanitise($name);
$subject = sanitise($subject);
$message = sanitise($message);
$data = "
Name: $name
Subject: $subject
Message: $message
###
";
$fh = fopen($file, 'a');
fwrite($fh, $data);
fclose($fh);
}
function get_entries($order = 'desc') {
global $file;
$data = file_get_contents($file);
$blocks = explode('###', $data);
$entries = array();
foreach($blocks as $entry) {
preg_match_all('#Name: (.+)\sSubject: (.+)\sMessage: (.+)#s', $entry, $matches);
if(empty($matches[1][0])) continue;
$name = trim($matches[1][0]);
$subject = trim($matches[2][0]);
$message = trim($matches[3][0]);
$entries[] = compact('name', 'subject', 'message');
}
return ($order == 'desc') ? array_reverse($entries) : $entries;
}
if(!empty($_POST['message'])) {
add_entry($_POST['name'], $_POST['subject'], $_POST['message']);
}
// Example presentation:
$entries = get_entries();
foreach($entries as $entry) {
extract($entry);
echo "
<div class='entry'>
<h3>$subject</h3>
<p><cite>by $name</cite></p>
<p>$message</p>
</div>
";
}
?>
Things I've added/changed:
- Want to change the filename in which your entries are stored? Just change it in one place - you could (and ideally should) switch this to a central config file.
- Abstraction! If in future you want to change the way you store your entries, you just need to edit the add_entry and get_entries methods, and don't need to touch your presentation logic. Your presentational code doesn't care whether you're getting the entries from a database or a text file, it just knows there'll be an array with fields called "name", "subject" and "message", something you can return from any sort of data storage.
- Sanitising of user input. Letting users add HTML/Javascript to your page isn't sensible
- Sorting. Self explanatory.
Any time you want to add an entry, call
Code:
add_entry('some name', 'a subject', 'the message you want to add');
or just POST variables called
name,
subject and
message to that script and it'll add one for you.
You can spice up the display yourself and change the sort order by passing 'asc' to get_entries() instead of the default 'desc'.
Hope this helps, even if it is total overkill