PHP fopen prepend

Soldato
Joined
21 Apr 2003
Posts
4,328
...as opposed to append.

Basically taking input from a web form, and appending it to a text file, which is being used as a simple guestbook. But I'd like the posts to appear at the top of the text file, instead of the bottom.

Seeing as fopen doesn't support this, is the only way to do this by copying the file into a temporary file, writing the new entry into the main file, then appending the temp file back on?
 
Fat lot of help you all are! :p

I've had a go, but is this still going to be viable as the size of the text file grows?

Code:
			$oldentries = file_get_contents("../guestbook.txt");

			$gBook = "../guestbook.txt";
			$wri = fopen($gBook, 'w') or die("Blaaarruuugghh!");

			$stringData = "<div class=\"gbentry\">\n";
			fwrite($wri, $stringData);
			$stringData = " <i>$date</i>\n <br /> <b>Name:</b> $name\n <br /><b>Subject:</b> $subject\n <br /><b>Message:</b> $text\n<br />\n";
			fwrite($wri, $stringData);
			$stringData = "</div>\n<br />\n";
			fwrite($wri, $stringData);

			fclose($wri);

			$app = fopen($gBook, 'a') or die("Blaaarruuugghh!");
			fwrite($app, $oldentries);

			fclose($app);
 
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('#', '&pound;', 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:

  1. 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.
  2. 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.
  3. Sanitising of user input. Letting users add HTML/Javascript to your page isn't sensible :p
  4. 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 :o
 
Last edited:
Oh blimey, two glasses of wine can't cope with all that!

Earlier today though, I did have a good old fiddle with what I had done.

Let me show you - this is not only the 'post to guestbook' part, there's image validation and emailing going on here too:

Code:
<?php

include "settings.php";

session_start();
$string = strtoupper($_SESSION['string']);
$userstring = strtoupper($_POST['userstring']); 
session_destroy();

$date=date('D jS \of F, Y - H:i:s');

if (($string == $userstring) && (strlen($string) > 4)) {

	if ( empty($name) || empty($email) || empty($subject) || empty($text) ) {
		header("Location: $failure");
		exit();
	}
	else {

		$allowedTags='<a><b><i><u>';
		$source = strip_tags($source, $allowedTags);

	        @extract($_POST);
		$name = strip_tags(stripslashes($name), $allowedTags);
		$email = stripslashes($email);
		$subject = strip_tags(stripslashes($subject), $allowedTags);
		$text = strip_tags(stripslashes($text), $allowedTags);

		mail('[email protected]',$subject." [".$book."]",$text,"From: $name <$email>");

		if ( isset($book) ) {

			$text = nl2br($text);

			$oldentries = file_get_contents("../guestbook.txt");

			$gBook = "../guestbook.txt";
			$wri = fopen($gBook, 'w') or die("Blaaarruuugghh!");

			$stringData = "<div class=\"gbentry\">\n";
			fwrite($wri, $stringData);
			$stringData = " <i>$date</i>\n <br /> <b>Name:</b> $name\n <br /><b>Subject:</b> $subject\n <br /><b>Message:</b> $text\n<br />\n";
			fwrite($wri, $stringData);
			$stringData = "</div>\n<br />\n";
			fwrite($wri, $stringData);

			fclose($wri);

			$app = fopen($gBook, 'a') or die("Blaaarruuugghh!");
			fwrite($app, $oldentries);

			fclose($app);
		}
		header("Location: $success");
		exit();
	}

} 

else {
	header("Location: $failure");
	exit();
}

?>

The page it's all for is http://www.sarawallen.com/contact/

Simply, I'm pulling the text file straight into the HTML with a 'require()' function, which is why all that formatting is going in too.

XML, parsing... that's for me to learn another time I think :p
 
Back
Top Bottom